diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..4bb1e696 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + "plugins": [ ], + "extends": [ + "eslint:recommended" + ], + "parser": "babel-eslint", + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "node": true, + "jquery": true + } + }; \ No newline at end of file diff --git a/.jsbeautifyrc b/.jsbeautifyrc new file mode 100644 index 00000000..1c15d387 --- /dev/null +++ b/.jsbeautifyrc @@ -0,0 +1,16 @@ +{ + "indent_size": 2 + , "indent_char": " " + , "comma_first": true + , "keep-array-indentation": true + , "space_after_named_function": true + , "space_after_anon_function": true + , "end_with_newline": true + , "brace_style": "collapse,preserve-inline" + , "space_in_brace": true + , "space-in-paren": false + , "break-chained-methods": false + , "max-preserve-newlines": 2 + , "space-after-anon-function": false + , "indent-empty-lines": false +} diff --git a/lib/admin_plugins/cleanstatusdb.js b/lib/admin_plugins/cleanstatusdb.js index b3e3032c..29fb99ba 100644 --- a/lib/admin_plugins/cleanstatusdb.js +++ b/lib/admin_plugins/cleanstatusdb.js @@ -8,60 +8,60 @@ var cleanstatusdb = { , pluginType: 'admin' }; -function init() { +function init () { return cleanstatusdb; } module.exports = init; cleanstatusdb.actions = [ - { - name: 'Delete all documents from devicestatus collection' - , description: 'This task removes all documents from devicestatus collection. Useful when uploader battery status is not properly updated.' - , buttonLabel: 'Delete all documents' - , confirmText: 'Delete all documents from devicestatus collection?' + { + name: 'Delete all documents from devicestatus collection' + , description: 'This task removes all documents from devicestatus collection. Useful when uploader battery status is not properly updated.' + , buttonLabel: 'Delete all documents' + , confirmText: 'Delete all documents from devicestatus collection?' } - , { - name: 'Delete all documents from devicestatus collection older than 30 days' - , description: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - , buttonLabel: 'Delete old documents' - , confirmText: 'Delete old documents from devicestatus collection?' - , preventClose: true + , { + name: 'Delete all documents from devicestatus collection older than 30 days' + , description: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' + , buttonLabel: 'Delete old documents' + , confirmText: 'Delete old documents from devicestatus collection?' + , preventClose: true } ]; -cleanstatusdb.actions[0].init = function init(client, callback) { +cleanstatusdb.actions[0].init = function init (client, callback) { var translate = client.translate; var $status = $('#admin_' + cleanstatusdb.name + '_0_status'); - + $status.hide().text(translate('Loading database ...')).fadeIn('slow'); $.ajax('/api/v1/devicestatus.json?count=500', { headers: client.headers() - , success: function (records) { + , success: function(records) { var recs = (records.length === 500 ? '500+' : records.length); - $status.hide().text(translate('Database contains %1 records',{ params: [recs] })).fadeIn('slow'); + $status.hide().text(translate('Database contains %1 records', { params: [recs] })).fadeIn('slow'); } - , error: function () { + , error: function() { $status.hide().text(translate('Error loading database')).fadeIn('slow'); } - }).done(function () { if (callback) { callback(); } }); + }).done(function() { if (callback) { callback(); } }); }; -cleanstatusdb.actions[0].code = function deleteRecords(client, callback) { +cleanstatusdb.actions[0].code = function deleteRecords (client, callback) { var translate = client.translate; var $status = $('#admin_' + cleanstatusdb.name + '_0_status'); - + if (!client.hashauth.isAuthenticated()) { alert(translate('Your device is not authenticated yet')); if (callback) { callback(); } return; - }; + } $status.hide().text(translate('Deleting records ...')).fadeIn('slow'); $.ajax({ - method: 'DELETE' + method: 'DELETE' , url: '/api/v1/devicestatus/*' , headers: client.headers() }).done(function success () { @@ -69,7 +69,7 @@ cleanstatusdb.actions[0].code = function deleteRecords(client, callback) { if (callback) { callback(); } - }).fail(function fail() { + }).fail(function fail () { $status.hide().text(translate('Error')).fadeIn('slow'); if (callback) { callback(); @@ -77,24 +77,24 @@ cleanstatusdb.actions[0].code = function deleteRecords(client, callback) { }); }; -cleanstatusdb.actions[1].init = function init(client, callback) { +cleanstatusdb.actions[1].init = function init (client, callback) { var translate = client.translate; var $status = $('#admin_' + cleanstatusdb.name + '_1_status'); $status.hide(); - var numDays = '
' - + ''; + var numDays = '
' + + ''; $('#admin_' + cleanstatusdb.name + '_1_html').html(numDays); if (callback) { callback(); } }; -cleanstatusdb.actions[1].code = function deleteOldRecords(client, callback) { +cleanstatusdb.actions[1].code = function deleteOldRecords (client, callback) { var translate = client.translate; var $status = $('#admin_' + cleanstatusdb.name + '_1_status'); var numDays = Number($('#admin_devicestatus_days').val()); @@ -117,17 +117,17 @@ cleanstatusdb.actions[1].code = function deleteOldRecords(client, callback) { $status.hide().text(translate('Deleting records ...')).fadeIn('slow'); $.ajax('/api/v1/devicestatus/?find[created_at][$lte]=' + dateStr, { - method: 'DELETE' + method: 'DELETE' , headers: client.headers() - , success: function (retVal) { - $status.text(translate('%1 records deleted',{ params: [retVal.n] })); + , success: function(retVal) { + $status.text(translate('%1 records deleted', { params: [retVal.n] })); } - , error: function () { + , error: function() { $status.hide().text(translate('Error')).fadeIn('slow'); } }).done(function success () { if (callback) { callback(); } - }).fail(function fail() { + }).fail(function fail () { if (callback) { callback(); } }); }; diff --git a/lib/admin_plugins/futureitems.js b/lib/admin_plugins/futureitems.js index 3d5acc23..4ea613a5 100644 --- a/lib/admin_plugins/futureitems.js +++ b/lib/admin_plugins/futureitems.js @@ -6,164 +6,164 @@ var futureitems = { , pluginType: 'admin' }; -function init() { +function init () { return futureitems; } module.exports = init; futureitems.actions = [ - { - name: 'Find and remove treatments in the future' - , description: 'This task find and remove treatments in the future.' - , buttonLabel: 'Remove treatments in the future' + { + name: 'Find and remove treatments in the future' + , description: 'This task find and remove treatments in the future.' + , buttonLabel: 'Remove treatments in the future' } - , { - name: 'Find and remove entries in the future' - , description: 'This task find and remove CGM data in the future created by uploader with wrong date/time.' - , buttonLabel: 'Remove entries in the future' + + , { + name: 'Find and remove entries in the future' + , description: 'This task find and remove CGM data in the future created by uploader with wrong date/time.' + , buttonLabel: 'Remove entries in the future' } ]; -futureitems.actions[0].init = function init(client, callback) { +futureitems.actions[0].init = function init (client, callback) { var translate = client.translate; var $status = $('#admin_' + futureitems.name + '_0_status'); - + function valueOrEmpty (value) { return value ? value : ''; } - + function showOneTreatment (tr, table) { - table.append($('').css('background-color','#0f0f0f') - .append($('').attr('width','20%').append(new Date(tr.created_at).toLocaleString().replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3'))) - .append($('').attr('width','20%').append(tr.eventType ? translate(client.careportal.resolveEventName(tr.eventType)) : '')) - .append($('').attr('width','10%').attr('align','center').append(tr.glucose ? tr.glucose + ' ('+translate(tr.glucoseType)+')' : '')) - .append($('').attr('width','10%').attr('align','center').append(valueOrEmpty(tr.insulin))) - .append($('').attr('width','10%').attr('align','center').append(valueOrEmpty(tr.carbs))) - .append($('').attr('width','10%').append(valueOrEmpty(tr.enteredBy))) - .append($('').attr('width','20%').append(valueOrEmpty(tr.notes))) + table.append($('').css('background-color', '#0f0f0f') + .append($('').attr('width', '20%').append(new Date(tr.created_at).toLocaleString().replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3'))) + .append($('').attr('width', '20%').append(tr.eventType ? translate(client.careportal.resolveEventName(tr.eventType)) : '')) + .append($('').attr('width', '10%').attr('align', 'center').append(tr.glucose ? tr.glucose + ' (' + translate(tr.glucoseType) + ')' : '')) + .append($('').attr('width', '10%').attr('align', 'center').append(valueOrEmpty(tr.insulin))) + .append($('').attr('width', '10%').attr('align', 'center').append(valueOrEmpty(tr.carbs))) + .append($('').attr('width', '10%').append(valueOrEmpty(tr.enteredBy))) + .append($('').attr('width', '20%').append(valueOrEmpty(tr.notes))) ); } - - function showTreatments(treatments, table) { - table.append($('').css('background','#040404') - .append($('').css('width','80px').attr('align','left').append(translate('Time'))) - .append($('').css('width','150px').attr('align','left').append(translate('Event Type'))) - .append($('').css('width','150px').attr('align','left').append(translate('Blood Glucose'))) - .append($('').css('width','50px').attr('align','left').append(translate('Insulin'))) - .append($('').css('width','50px').attr('align','left').append(translate('Carbs'))) - .append($('').css('width','150px').attr('align','left').append(translate('Entered By'))) - .append($('').css('width','300px').attr('align','left').append(translate('Notes'))) + + function showTreatments (treatments, table) { + table.append($('').css('background', '#040404') + .append($('').css('width', '80px').attr('align', 'left').append(translate('Time'))) + .append($('').css('width', '150px').attr('align', 'left').append(translate('Event Type'))) + .append($('').css('width', '150px').attr('align', 'left').append(translate('Blood Glucose'))) + .append($('').css('width', '50px').attr('align', 'left').append(translate('Insulin'))) + .append($('').css('width', '50px').attr('align', 'left').append(translate('Carbs'))) + .append($('').css('width', '150px').attr('align', 'left').append(translate('Entered By'))) + .append($('').css('width', '300px').attr('align', 'left').append(translate('Notes'))) ); - for (var t=0; t').css('margin-top','10px'); + $status.hide().text(translate('Database contains %1 future records', { params: [records.length] })).fadeIn('slow'); + var table = $('').css('margin-top', '10px'); $('#admin_' + futureitems.name + '_0_html').append(table); showTreatments(records, table); futureitems.actions[0].confirmText = translate('Remove %1 selected records?', { params: [records.length] }); } - , error: function () { + , error: function() { $status.hide().text(translate('Error loading database')).fadeIn('slow'); futureitems.treatmentrecords = []; } - }).done(function () { if (callback) { callback(); } }); + }).done(function() { if (callback) { callback(); } }); }; -futureitems.actions[0].code = function deleteRecords(client, callback) { +futureitems.actions[0].code = function deleteRecords (client, callback) { var translate = client.translate; var $status = $('#admin_' + futureitems.name + '_0_status'); - + if (!client.hashauth.isAuthenticated()) { alert(translate('Your device is not authenticated yet')); if (callback) { callback(); } return; - }; + } function deleteRecordById (_id) { $.ajax({ - method: 'DELETE' + method: 'DELETE' , url: '/api/v1/treatments/' + _id , headers: client.headers() }).done(function success () { $status.text(translate('Record %1 removed ...', { params: [_id] })); - }).fail(function fail() { - $status.text(translate('Error removing record %1', { params: [_id] })); + }).fail(function fail () { + $status.text(translate('Error removing record %1', { params: [_id] })); }); } - + $status.hide().text(translate('Deleting records ...')).fadeIn('slow'); for (var i = 0; i < futureitems.treatmentrecords.length; i++) { deleteRecordById(futureitems.treatmentrecords[i]._id); } $('#admin_' + futureitems.name + '_0_html').html(''); - + if (callback) { callback(); } }; -futureitems.actions[1].init = function init(client, callback) { +futureitems.actions[1].init = function init (client, callback) { var translate = client.translate; var $status = $('#admin_' + futureitems.name + '_1_status'); - + $status.hide().text(translate('Loading database ...')).fadeIn('slow'); var now = new Date().getTime(); $.ajax('/api/v1/entries.json?&find[date][$gte]=' + now + '&count=288', { headers: client.headers() - , success: function (records) { + , success: function(records) { futureitems.entriesrecords = records; - $status.hide().text(translate('Database contains %1 future records',{ params: [records.length] })).fadeIn('slow'); + $status.hide().text(translate('Database contains %1 future records', { params: [records.length] })).fadeIn('slow'); futureitems.actions[1].confirmText = translate('Remove %1 selected records?', { params: [records.length] }); } - , error: function () { + , error: function() { $status.hide().text(translate('Error loading database')).fadeIn('slow'); futureitems.entriesrecords = []; } - }).done(function () { if (callback) { callback(); } }); + }).done(function() { if (callback) { callback(); } }); }; -futureitems.actions[1].code = function deleteRecords(client, callback) { +futureitems.actions[1].code = function deleteRecords (client, callback) { var translate = client.translate; var $status = $('#admin_' + futureitems.name + '_1_status'); - + if (!client.hashauth.isAuthenticated()) { alert(translate('Your device is not authenticated yet')); if (callback) { callback(); } return; - }; - + } + function deteleteRecordById (_id) { $.ajax({ - method: 'DELETE' + method: 'DELETE' , url: '/api/v1/entries/' + _id , headers: client.headers() }).done(function success () { $status.text(translate('Record %1 removed ...', { params: [_id] })); - }).fail(function fail() { - $status.text(translate('Error removing record %1', { params: [_id] })); + }).fail(function fail () { + $status.text(translate('Error removing record %1', { params: [_id] })); }); } - $status.hide().text(translate('Deleting records ...')).fadeIn('slow'); for (var i = 0; i < futureitems.entriesrecords.length; i++) { deteleteRecordById(futureitems.entriesrecords[i]._id); } - + if (callback) { callback(); } diff --git a/lib/admin_plugins/roles.js b/lib/admin_plugins/roles.js index 42191751..f99c4344 100644 --- a/lib/admin_plugins/roles.js +++ b/lib/admin_plugins/roles.js @@ -1,12 +1,14 @@ 'use strict'; +const _ = require('lodash'); + var roles = { name: 'roles' , label: 'Roles - Groups of People, Devices, etc' , pluginType: 'admin' }; -function init() { +function init () { return roles; } @@ -20,13 +22,13 @@ roles.actions = [{ , init: function init (client, callback) { $status = $('#admin_' + roles.name + '_0_status'); $status.hide().text(client.translate('Loading database ...')).fadeIn('slow'); - var table = $('
').css('margin-top','10px'); + var table = $('
').css('margin-top', '10px'); $('#admin_' + roles.name + '_0_html').append(table).append(genDialog(client)); reload(client, callback); } , preventClose: true , code: function createNewRole (client, callback) { - var role = { }; + var role = {}; openDialog(role, client, callback); } }]; @@ -40,9 +42,9 @@ function createOrSaveRole (role, client, callback) { , url: '/api/v2/authorization/roles/' , headers: client.headers() , data: role - }).done(function success() { + }).done(function success () { reload(client, callback); - }).fail(function fail(err) { + }).fail(function fail (err) { console.error('Unable to ' + method + ' Role', err.responseText); window.alert(client.translate('Unable to %1 Role', { params: [method] })); if (callback) { @@ -56,9 +58,9 @@ function deleteRole (role, client, callback) { method: 'DELETE' , url: '/api/v2/authorization/roles/' + role._id , headers: client.headers() - }).done(function success() { + }).done(function success () { reload(client, callback); - }).fail(function fail(err) { + }).fail(function fail (err) { console.error('Unable to delete Role', err.responseText); window.alert(client.translate('Unable to delete Role')); if (callback) { @@ -70,16 +72,16 @@ function deleteRole (role, client, callback) { function reload (client, callback) { $.ajax({ method: 'GET' - , url:'/api/v2/authorization/roles' + , url: '/api/v2/authorization/roles' , headers: client.headers() }).done(function success (records) { roles.records = records; - $status.hide().text(client.translate('Database contains %1 roles',{ params: [records.length] })).fadeIn('slow'); + $status.hide().text(client.translate('Database contains %1 roles', { params: [records.length] })).fadeIn('slow'); showRoles(records, client); if (callback) { callback(); } - }).fail(function fail(err) { + }).fail(function fail (err) { $status.hide().text(client.translate('Error loading database')).fadeIn('slow'); roles.records = []; if (callback) { @@ -90,56 +92,57 @@ function reload (client, callback) { function genDialog (client) { var ret = - '' - ; + ''; return $(ret); } function openDialog (role, client) { - $( '#editroledialog' ).dialog({ + $('#editroledialog').dialog({ width: 360 , height: 360 - , buttons: [ - { text: client.translate('Save'), - class: 'leftButton', - click: function() { + , buttons: [ + { + text: client.translate('Save') + , class: 'leftButton' + , click: function() { role.name = $('#edrole_name').val(); role.permissions = _.chain($('#edrole_permissions').val().toLowerCase().split(/[;, ]/)) - .map(_.trim) - .reject(_.isEmpty) - .sort() - .value(); + .map(_.trim) + .reject(_.isEmpty) + .sort() + .value(); role.notes = $('#edrole_notes').val(); var self = this; delete role.autoGenerated; createOrSaveRole(role, client, function callback () { - $( self ).dialog('close'); + $(self).dialog('close'); }); } - }, - { text: client.translate('Cancel'), - click: function () { $( this ).dialog('close'); } + } + , { + text: client.translate('Cancel') + , click: function() { $(this).dialog('close'); } } ] - , open : function() { + , open: function() { $(this).parent().css('box-shadow', '20px 20px 20px 0px black'); - $(this).parent().find('.ui-dialog-buttonset' ).css({'width':'100%','text-align':'right'}); - $(this).parent().find('button:contains("'+client.translate('Save')+'")').css({'float':'left'}); + $(this).parent().find('.ui-dialog-buttonset').css({ 'width': '100%', 'text-align': 'right' }); + $(this).parent().find('button:contains("' + client.translate('Save') + '")').css({ 'float': 'left' }); $('#edrole_name').val(role.name || '').focus(); $('#edrole_permissions').val(role.permissions ? role.permissions.join(' ') : ''); $('#edrole_notes').val(role.notes || ''); @@ -151,14 +154,14 @@ function openDialog (role, client) { function showRole (role, table, client) { var editIcon = $(''); - editIcon.click(function clicked ( ) { + editIcon.click(function clicked () { openDialog(role, client); }); var deleteIcon = ''; if (role._id) { deleteIcon = $(''); - deleteIcon.click(function clicked() { + deleteIcon.click(function clicked () { var ok = window.confirm(client.translate('Are you sure you want to delete: ') + role.name); if (ok) { deleteRole(role, client); @@ -166,21 +169,21 @@ function showRole (role, table, client) { }); } - table.append($('').css('background-color','#0f0f0f') - .append($('').css('background-color', '#0f0f0f') + .append($('').css('background','#040404') - .append($('').css('background', '#040404') + .append($('').appendTo(table); $('').appendTo(table); $('').appendTo(table); - + $('').appendTo(table); $('#daytodaystatchart-' + day).append(table); var chartData = [ { - label: translate('Basal'), - count: totalBasalInsulin, - pct: (totalBasalInsulin / totalDailyInsulin * 100).toFixed(0) - }, - {label: translate('Bolus'), count: bolusInsulin, pct: (bolusInsulin / totalDailyInsulin * 100).toFixed(0)} + label: translate('Basal') + , count: totalBasalInsulin + , pct: (totalBasalInsulin / totalDailyInsulin * 100).toFixed(0) + } + , { label: translate('Bolus'), count: bolusInsulin, pct: (bolusInsulin / totalDailyInsulin * 100).toFixed(0) } ]; // Insulin distribution chart @@ -937,98 +932,98 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) var color = d3.scale.ordinal().range([basalcolor, boluscolor]); var labelArc = d3.svg.arc() - .outerRadius(radius / 2) - .innerRadius(radius / 2); + .outerRadius(radius / 2) + .innerRadius(radius / 2); var svg = d3.select('#daytodaystatinsulinpiechart-' + day) - .append('svg') - .attr('width', width) - .attr('height', height) - .append('g') - .attr('transform', 'translate(' + (width / 2) + - ',' + (height / 2) + ')'); + .append('svg') + .attr('width', width) + .attr('height', height) + .append('g') + .attr('transform', 'translate(' + (width / 2) + + ',' + (height / 2) + ')'); var arc = d3.svg.arc() - .outerRadius(radius); + .outerRadius(radius); var pie = d3.layout.pie() - .value(function (d) { - return d.count; - }) - .sort(null); + .value(function(d) { + return d.count; + }) + .sort(null); var insulg = svg.selectAll('.insulinarc') - .data(pie(chartData)) - .enter() - .append('g') - .attr('class', 'insulinarc'); + .data(pie(chartData)) + .enter() + .append('g') + .attr('class', 'insulinarc'); insulg.append('path') - .attr('d', arc) - .attr('opacity', '0.5') - .attr('fill', function (d) { - return color(d.data.label); - }); + .attr('d', arc) + .attr('opacity', '0.5') + .attr('fill', function(d) { + return color(d.data.label); + }); insulg.append('text') - .attr('transform', function (d) { - return 'translate(' + labelArc.centroid(d) + ')'; - }) - .attr('dy', '.15em') - .style('font-weight', 'bold') - .attr('text-anchor', 'middle') - .text(function (d) { - return d.data.pct + '%'; - }); + .attr('transform', function(d) { + return 'translate(' + labelArc.centroid(d) + ')'; + }) + .attr('dy', '.15em') + .style('font-weight', 'bold') + .attr('text-anchor', 'middle') + .text(function(d) { + return d.data.pct + '%'; + }); // Carbs pie chart var carbscolor = d3.scale.ordinal().range(['red']); var carbsData = [ - {label: translate('Carbs'), count: data.dailyCarbs} + { label: translate('Carbs'), count: data.dailyCarbs } ]; var carbssvg = d3.select('#daytodaystatcarbspiechart-' + day) - .append('svg') - .attr('width', width) - .attr('height', height) - .append('g') - .attr('transform', 'translate(' + (width / 2) + - ',' + (height / 2) + ')'); + .append('svg') + .attr('width', width) + .attr('height', height) + .append('g') + .attr('transform', 'translate(' + (width / 2) + + ',' + (height / 2) + ')'); var carbsarc = d3.svg.arc() - .outerRadius(radius * data.dailyCarbs / options.maxDailyCarbsValue); + .outerRadius(radius * data.dailyCarbs / options.maxDailyCarbsValue); var carbspie = d3.layout.pie() - .value(function (d) { - return d.count; - }) - .sort(null); + .value(function(d) { + return d.count; + }) + .sort(null); var carbsg = carbssvg.selectAll('.carbsarc') - .data(carbspie(carbsData)) - .enter() - .append('g') - .attr('class', 'carbsarc'); + .data(carbspie(carbsData)) + .enter() + .append('g') + .attr('class', 'carbsarc'); carbsg.append('path') - .attr('d', carbsarc) - .attr('opacity', '0.5') - .attr('fill', function (d) { - return carbscolor(d.data.label); - }); + .attr('d', carbsarc) + .attr('opacity', '0.5') + .attr('fill', function(d) { + return carbscolor(d.data.label); + }); carbsg.append('text') - .attr('transform', function () { - return 'translate(0,0)'; - }) - .attr('dy', '.15em') - .style('font-weight', 'bold') - .attr('text-anchor', 'middle') - .text(function (d) { - return d.data.count + 'g'; - }); + .attr('transform', function() { + return 'translate(0,0)'; + }) + .attr('dy', '.15em') + .style('font-weight', 'bold') + .attr('text-anchor', 'middle') + .text(function(d) { + return d.data.count + 'g'; + }); } tddSum += totalDailyInsulin; @@ -1043,15 +1038,15 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) , first: true }); - function appendProfileSwitch(context, treatment) { - + function appendProfileSwitch (context, treatment) { + if (!treatment.cutting && !treatment.profile) { return; } - + var sign = treatment.first ? '▲▲▲' : '▬▬▬'; var text; if (treatment.cutting) { text = sign + ' ' + client.profilefunctions.profileSwitchName(treatment.cutting) + ' ' + '►►►' + ' ' + client.profilefunctions.profileSwitchName(treatment.profile) + ' ' + sign; - } else { + } else { text = sign + ' ' + client.profilefunctions.profileSwitchName(treatment.profile) + ' ' + sign; } context.append('text') @@ -1060,7 +1055,7 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .attr('fill', '#0099ff') .attr('text-anchor', 'start') .attr('dy', '.35em') - .attr('transform', 'rotate(-90 ' + (xScale2(treatment.mills) + padding.left) + ',' + (yScaleBasals(0) + padding.top - 10) + ') ' + + .attr('transform', 'rotate(-90 ' + (xScale2(treatment.mills) + padding.left) + ',' + (yScaleBasals(0) + padding.top - 10) + ') ' + 'translate(' + (xScale2(treatment.mills) + padding.left) + ',' + (yScaleBasals(0) + padding.top - 10) + ')') .text(text); } @@ -1068,7 +1063,7 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) console.log("Rendering " + day, new Date().getTime() - timestart.getTime(), "msecs"); } - function hideTooltip ( ) { + function hideTooltip () { client.tooltip.transition() .duration(TOOLTIP_TRANS_MS) .style('opacity', 0); diff --git a/lib/report_plugins/glucosedistribution.js b/lib/report_plugins/glucosedistribution.js index 5669d5c1..4a5e7dd3 100644 --- a/lib/report_plugins/glucosedistribution.js +++ b/lib/report_plugins/glucosedistribution.js @@ -6,13 +6,13 @@ var glucosedistribution = { , pluginType: 'report' }; -function init() { +function init () { return glucosedistribution; } module.exports = init; -glucosedistribution.html = function html(client) { +glucosedistribution.html = function html (client) { var translate = client.translate; var ret = '

' + @@ -65,8 +65,7 @@ glucosedistribution.html = function html(client) { '20' + '21' + '22' + - '23' - ; + '23'; return ret; }; @@ -83,7 +82,7 @@ glucosedistribution.css = ' text-align:center;' + '}'; -glucosedistribution.report = function report_glucosedistribution(datastorage, sorteddaystoshow, options) { +glucosedistribution.report = function report_glucosedistribution (datastorage, sorteddaystoshow, options) { var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; @@ -132,13 +131,13 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so // Filter data for noise // data cleaning pass 0 - remove duplicates and non-sgv entries, sort - var seen = {}; + var seen = []; data = data.filter(function(item) { - if (!item.sgv || !item.bgValue || !item.displayTime || item.bgValue < 39) { + if (!item.sgv || !item.bgValue || !item.displayTime || item.bgValue < 39) { console.log(item); return false; } - return seen.hasOwnProperty(item.displayTime) ? false : (seen[item.displayTime] = true); + return seen.includes(item.displayTime) ? false : (seen[item.displayTime] = true); }); data.sort(function(a, b) { @@ -148,7 +147,7 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so var glucose_data = [data[0]]; // data cleaning pass 1 - add interpolated missing points - for (var i = 0; i <= data.length - 2; i++) { + for (i = 0; i <= data.length - 2; i++) { var entry = data[i]; var nextEntry = data[i + 1]; @@ -186,12 +185,12 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so const maxGap = (5 * 60 * 1000) + 10000; - for (var i = 1; i <= glucose_data.length - 2; i++) { - var entry = glucose_data[i]; - var nextEntry = glucose_data[i + 1]; + for (i = 1; i <= glucose_data.length - 2; i++) { + let entry = glucose_data[i]; + let nextEntry = glucose_data[i + 1]; - var timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); - var timeDelta2 = entry.displayTime.getTime() - prevEntry.displayTime.getTime(); + let timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); + let timeDelta2 = entry.displayTime.getTime() - prevEntry.displayTime.getTime(); if (timeDelta > maxGap || timeDelta2 > maxGap) { glucose_data2.push(entry); @@ -212,8 +211,8 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so const d = (nextEntry.bgValue - prevEntry.bgValue) / 2; const interpolatedValue = prevEntry.bgValue + d; - var newEntry = { - sgv: displayUnits === 'mmol' ? interpolatedValue/18 : interpolatedValue + let newEntry = { + sgv: displayUnits === 'mmol' ? interpolatedValue / 18 : interpolatedValue , bgValue: interpolatedValue , displayTime: entry.displayTime }; @@ -237,10 +236,10 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so }); var timeTotal = 0; - for (var i = 1; i <= glucose_data.length - 2; i++) { - var entry = glucose_data[i]; - var nextEntry = glucose_data[i + 1]; - var timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); + for (i = 1; i <= glucose_data.length - 2; i++) { + let entry = glucose_data[i]; + let nextEntry = glucose_data[i + 1]; + let timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); if (timeDelta < maxGap) { timeTotal += timeDelta; } @@ -357,11 +356,10 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so var glucoseTotal = 0; var deltaTotal = 0; - for (var i = 0; i <= glucose_data.length - 2; i++) { - var entry = glucose_data[i]; - var nextEntry = glucose_data[i + 1]; - - var timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); + for (i = 0; i <= glucose_data.length - 2; i++) { + const entry = glucose_data[i]; + const nextEntry = glucose_data[i + 1]; + const timeDelta = nextEntry.displayTime.getTime() - entry.displayTime.getTime(); // Use maxGap constant if (timeDelta == 0 || timeDelta > maxGap) { // 6 * 60 * 1000) { @@ -470,7 +468,7 @@ glucosedistribution.report = function report_glucosedistribution(datastorage, so ); }); - function onClick() { + function onClick () { report_glucosedistribution(datastorage, sorteddaystoshow, options); } }; diff --git a/lib/report_plugins/hourlystats.js b/lib/report_plugins/hourlystats.js index 12a44126..84114209 100644 --- a/lib/report_plugins/hourlystats.js +++ b/lib/report_plugins/hourlystats.js @@ -8,34 +8,33 @@ var hourlystats = { , pluginType: 'report' }; -function init() { +function init () { return hourlystats; } module.exports = init; -hourlystats.html = function html(client) { +hourlystats.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Hourly stats') + '

' - + '
' - + '
' - ; + '

' + translate('Hourly stats') + '

' + + '
' + + '
'; return ret; }; hourlystats.css = - '#hourlystats-overviewchart {' - + ' width: 100%;' - + ' min-width: 6.5in;' - + ' height: 5in;' - + '}' - + '#hourlystats-placeholder td {' - + ' text-align:center;' - + '}'; + '#hourlystats-overviewchart {' + + ' width: 100%;' + + ' min-width: 6.5in;' + + ' height: 5in;' + + '}' + + '#hourlystats-placeholder td {' + + ' text-align:center;' + + '}'; -hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, options) { -//console.log(window); +hourlystats.report = function report_hourlystats (datastorage, sorteddaystoshow, options) { + //console.log(window); var ss = require('simple-statistics'); var Nightscout = window.Nightscout; var client = Nightscout.client; @@ -52,15 +51,15 @@ hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, pivotedByHour[i] = []; } - data = data.filter(function(o) { return !isNaN(o.sgv);}); - + data = data.filter(function(o) { return !isNaN(o.sgv); }); + data.forEach(function(record) { var d = new Date(record.displayTime); record.sgv = Number(record.sgv); pivotedByHour[d.getHours()].push(record); }); - + var table = $('
').attr('width','20%').append(editIcon).append(deleteIcon).append(role.name)) - .append($('').attr('width','20%').append(_.isEmpty(role.permissions) ? '[none]' : role.permissions.join(' '))) - .append($('').attr('width','10%').append(role._id ? (role.notes ? role.notes : '') : '[system default]')) + table.append($('
').attr('width', '20%').append(editIcon).append(deleteIcon).append(role.name)) + .append($('').attr('width', '20%').append(_.isEmpty(role.permissions) ? '[none]' : role.permissions.join(' '))) + .append($('').attr('width', '10%').append(role._id ? (role.notes ? role.notes : '') : '[system default]')) ); } function showRoles (roles, client) { var table = $('#admin_roles_table'); - table.empty().append($('
').css('width','100px').attr('align','left').append(client.translate('Name'))) - .append($('').css('width','150px').attr('align','left').append(client.translate('Permissions'))) - .append($('').css('width','150px').attr('align','left').append(client.translate('Notes'))) + table.empty().append($('
').css('width', '100px').attr('align', 'left').append(client.translate('Name'))) + .append($('').css('width', '150px').attr('align', 'left').append(client.translate('Permissions'))) + .append($('').css('width', '150px').attr('align', 'left').append(client.translate('Notes'))) ); - for (var t=0; t').css('margin-top','10px'); + var table = $('').css('margin-top', '10px'); $('#admin_' + subjects.name + '_0_html').append(table).append(genDialog(client)); reload(client, callback); } @@ -39,9 +41,9 @@ function createOrSaveSubject (subject, client, callback) { , url: '/api/v2/authorization/subjects/' , headers: client.headers() , data: subject - }).done(function success() { + }).done(function success () { reload(client, callback); - }).fail(function fail(err) { + }).fail(function fail (err) { console.error('Unable to ' + method + ' Subject', err.responseText); window.alert(client.translate('Unable to ' + method + ' Subject')); if (callback) { @@ -55,9 +57,9 @@ function deleteSubject (subject, client, callback) { method: 'DELETE' , url: '/api/v2/authorization/subjects/' + subject._id , headers: client.headers() - }).done(function success() { + }).done(function success () { reload(client, callback); - }).fail(function fail(err) { + }).fail(function fail (err) { console.error('Unable to delete Subject', err.responseText); window.alert(client.translate('Unable to delete Subject')); if (callback) { @@ -69,16 +71,16 @@ function deleteSubject (subject, client, callback) { function reload (client, callback) { $.ajax({ method: 'GET' - , url:'/api/v2/authorization/subjects' + , url: '/api/v2/authorization/subjects' , headers: client.headers() }).done(function success (records) { subjects.records = records; - $status.hide().text(client.translate('Database contains %1 subjects',{ params: [records.length] })).fadeIn('slow'); + $status.hide().text(client.translate('Database contains %1 subjects', { params: [records.length] })).fadeIn('slow'); showSubjects(records, client); if (callback) { callback(); } - }).fail(function fail(err) { + }).fail(function fail (err) { $status.hide().text(client.translate('Error loading database')).fadeIn('slow'); subjects.records = []; if (callback) { @@ -89,56 +91,57 @@ function reload (client, callback) { function genDialog (client) { var ret = - '' - ; + ''; return $(ret); } function openDialog (subject, client) { - $( '#editsubjectdialog' ).dialog({ + $('#editsubjectdialog').dialog({ width: 360 , height: 300 - , buttons: [ - { text: client.translate('Save'), - class: 'leftButton', - click: function() { + , buttons: [ + { + text: client.translate('Save') + , class: 'leftButton' + , click: function() { subject.name = $('#edsub_name').val(); subject.roles = _.chain($('#edsub_roles').val().toLowerCase().split(/[;, ]/)) - .map(_.trim) - .reject(_.isEmpty) - .sort() - .value(); + .map(_.trim) + .reject(_.isEmpty) + .sort() + .value(); subject.notes = $('#edsub_notes').val(); var self = this; - createOrSaveSubject(subject, client, function callback ( ) { - $( self ).dialog('close'); + createOrSaveSubject(subject, client, function callback () { + $(self).dialog('close'); }); } - }, - { text: client.translate('Cancel'), - click: function () { $( this ).dialog('close'); } + } + , { + text: client.translate('Cancel') + , click: function() { $(this).dialog('close'); } } ] - , open : function() { + , open: function() { $(this).parent().css('box-shadow', '20px 20px 20px 0px black'); - $(this).parent().find('.ui-dialog-buttonset' ).css({'width':'100%','text-align':'right'}); - $(this).parent().find('button:contains("'+client.translate('Save')+'")').css({'float':'left'}); + $(this).parent().find('.ui-dialog-buttonset').css({ 'width': '100%', 'text-align': 'right' }); + $(this).parent().find('button:contains("' + client.translate('Save') + '")').css({ 'float': 'left' }); $('#edsub_name').val(subject.name || '').focus(); $('#edsub_roles').val(subject.roles ? subject.roles.join(', ') : ''); $('#edsub_notes').val(subject.notes || ''); @@ -150,33 +153,33 @@ function openDialog (subject, client) { function showSubject (subject, table, client) { var editIcon = $(''); - editIcon.click(function clicked ( ) { + editIcon.click(function clicked () { openDialog(subject, client); }); var deleteIcon = $(''); - deleteIcon.click(function clicked ( ) { + deleteIcon.click(function clicked () { var ok = window.confirm(client.translate('Are you sure you want to delete: ') + subject.name); if (ok) { deleteSubject(subject, client); } }); - table.append($('').css('background-color','#0f0f0f') - .append($('').css('background-color', '#0f0f0f') + .append($('').css('background','#040404') - .append($('').css('background', '#040404') + .append($(''); $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); - $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); + $('').appendTo(thead); thead.appendTo(table); - sorteddaystoshow.forEach(function (day) { + sorteddaystoshow.forEach(function(day) { var tr = $(''); var daysRecords = datastorage[day].statsrecords; - + if (daysRecords.length === 0) { $('').appendTo(tr); - $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); table.append(tr); - return;; + return; } minForDay = daysRecords[0].sgv; @@ -101,53 +99,52 @@ dailystats.report = function report_dailystats(datastorage,sorteddaystoshow,opti sum += record.sgv; return out; }, { - lows: 0, - normal: 0, - highs: 0 + lows: 0 + , normal: 0 + , highs: 0 }); var average = sum / daysRecords.length; var bgValues = daysRecords.map(function(r) { return r.sgv; }); - $('').appendTo(tr); + $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); + $('').appendTo(tr); table.append(tr); var inrange = [ { - label: translate('Low'), - data: Math.round(stats.lows * 1000 / daysRecords.length) / 10 - }, - { - label: translate('In Range'), - data: Math.round(stats.normal * 1000 / daysRecords.length) / 10 - }, - { - label: translate('High'), - data: Math.round(stats.highs * 1000 / daysRecords.length) / 10 + label: translate('Low') + , data: Math.round(stats.lows * 1000 / daysRecords.length) / 10 + } + , { + label: translate('In Range') + , data: Math.round(stats.normal * 1000 / daysRecords.length) / 10 + } + , { + label: translate('High') + , data: Math.round(stats.highs * 1000 / daysRecords.length) / 10 } ]; $.plot( - '#dailystat-chart-' + day.toString(), - inrange, - { + '#dailystat-chart-' + day.toString() + , inrange, { series: { pie: { show: true } - }, - colors: ['#f88', '#8f8', '#ff8'] + } + , colors: ['#f88', '#8f8', '#ff8'] } ); }); diff --git a/lib/report_plugins/daytoday.js b/lib/report_plugins/daytoday.js index c0960576..5a100b4b 100644 --- a/lib/report_plugins/daytoday.js +++ b/lib/report_plugins/daytoday.js @@ -11,78 +11,77 @@ var daytoday = { , pluginType: 'report' }; -function init() { +function init () { return daytoday; } module.exports = init; -daytoday.html = function html(client) { +daytoday.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Day to day') + '

' - + '' + translate('To see this report, press SHOW while in this view') + '
' - + translate('Display') + ': ' - + ''+translate('Insulin')+'' - + ''+translate('Carbs')+'' - + ''+translate('Basal rate')+'' - + ''+translate('Notes') - + ''+translate('Food') - + ''+translate('Raw')+'' - + ''+translate('IOB')+'' - + ''+translate('COB')+'' - + ''+translate('Predictions')+'' - + ''+translate('OpenAPS')+'' - + ''+translate('Insulin distribution')+'' - + ' '+translate('Size') - + ' ' - + '
' - + translate('Scale') + ': ' - + '' - + translate('Linear') - + '' - + translate('Logarithmic') - + '' - + '
' - + '
' - + '
' - ; - return ret; + '

' + translate('Day to day') + '

' + + '' + translate('To see this report, press SHOW while in this view') + '
' + + translate('Display') + ': ' + + '' + translate('Insulin') + '' + + '' + translate('Carbs') + '' + + '' + translate('Basal rate') + '' + + '' + translate('Notes') + + '' + translate('Food') + + '' + translate('Raw') + '' + + '' + translate('IOB') + '' + + '' + translate('COB') + '' + + '' + translate('Predictions') + '' + + '' + translate('OpenAPS') + '' + + '' + translate('Insulin distribution') + '' + + ' ' + translate('Size') + + ' ' + + '
' + + translate('Scale') + ': ' + + '' + + translate('Linear') + + '' + + translate('Logarithmic') + + '' + + '
' + + '
' + + '
'; + return ret; }; -daytoday.prepareHtml = function daytodayPrepareHtml(sorteddaystoshow) { +daytoday.prepareHtml = function daytodayPrepareHtml (sorteddaystoshow) { $('#daytodaycharts').html(''); - sorteddaystoshow.forEach(function eachDay(d) { + sorteddaystoshow.forEach(function eachDay (d) { $('#daytodaycharts').append($('
').attr('width','20%').append(editIcon).append(deleteIcon).append(subject.name)) - .append($('').attr('width','20%').append(subject.roles ? subject.roles.join(', ') : '[none]')) - .append($('').attr('width','20%').append('' + subject.accessToken + '')) - .append($('').attr('width','10%').append(subject.notes ? subject.notes : '')) + table.append($('
').attr('width', '20%').append(editIcon).append(deleteIcon).append(subject.name)) + .append($('').attr('width', '20%').append(subject.roles ? subject.roles.join(', ') : '[none]')) + .append($('').attr('width', '20%').append('' + subject.accessToken + '')) + .append($('').attr('width', '10%').append(subject.notes ? subject.notes : '')) ); } function showSubjects (subjects, client) { var table = $('#admin_subjects_table'); - table.empty().append($('
').css('width','100px').attr('align','left').append(client.translate('Name'))) - .append($('').css('width','150px').attr('align','left').append(client.translate('Roles'))) - .append($('').css('width','150px').attr('align','left').append(client.translate('Access Token'))) - .append($('').css('width','150px').attr('align','left').append(client.translate('Notes'))) + table.empty().append($('
').css('width', '100px').attr('align', 'left').append(client.translate('Name'))) + .append($('').css('width', '150px').attr('align', 'left').append(client.translate('Roles'))) + .append($('').css('width', '150px').attr('align', 'left').append(client.translate('Access Token'))) + .append($('').css('width', '150px').attr('align', 'left').append(client.translate('Notes'))) ); - for (var t=0; t -1 - && client.settings.extendedSettings.profile - && client.settings.extendedSettings.profile.multiple - && profiles.length > 1; + function isProfileEnabled (profiles) { + return client.settings.enable.indexOf('profile') > -1 && + client.settings.extendedSettings.profile && + client.settings.extendedSettings.profile.multiple && + profiles.length > 1; } - function isTouch() { - try { document.createEvent('TouchEvent'); return true; } - catch (e) { return false; } + function isTouch () { + try { document.createEvent('TouchEvent'); return true; } catch (e) { return false; } } function setDateAndTime (time) { @@ -52,11 +51,11 @@ function init(client, $) { eventDate.val(time.format('YYYY-MM-DD')); } - function mergeDateAndTime ( ) { + function mergeDateAndTime () { return client.utils.mergeInputTime(eventTime.val(), eventDate.val()); } - function updateTime(ele, time) { + function updateTime (ele, time) { ele.attr('oldminutes', time.minutes()); ele.attr('oldhours', time.hours()); } @@ -98,15 +97,15 @@ function init(client, $) { } }; - boluscalc.dateTimeFocus = function dateTimeFocus(event) { + boluscalc.dateTimeFocus = function dateTimeFocus (event) { $('#bc_othertime').prop('checked', true); updateTime($(this), mergeDateAndTime()); maybePrevent(event); }; - boluscalc.dateTimeChange = function dateTimeChange(event) { + boluscalc.dateTimeChange = function dateTimeChange (event) { $('#bc_othertime').prop('checked', true); -// client.utils.setYAxisOffset(50); //50% of extend + // client.utils.setYAxisOffset(50); //50% of extend var ele = $(this); var merged = mergeDateAndTime(); @@ -126,29 +125,29 @@ function init(client, $) { boluscalc.calculateInsulin(); maybePrevent(event); -// Nightscout.utils.updateBrushToTime(moment.toDate()); + // Nightscout.utils.updateBrushToTime(moment.toDate()); }; - boluscalc.eventTimeTypeChange = function eventTimeTypeChange(event) { + boluscalc.eventTimeTypeChange = function eventTimeTypeChange (event) { if ($('#bc_othertime').is(':checked')) { $('#bc_eventTimeValue').focus(); - $('#bc_retro').css('display',''); - if (mergeDateAndTime()moment()) { - $('#bc_retro').css('background-color','blue').text(translate('IN THE FUTURE')); + $('#bc_retro').css('display', ''); + if (mergeDateAndTime() < moment()) { + $('#bc_retro').css('background-color', 'red').text(translate('RETRO MODE')); + } else if (mergeDateAndTime() > moment()) { + $('#bc_retro').css('background-color', 'blue').text(translate('IN THE FUTURE')); } else { - $('#bc_retro').css('display','none'); + $('#bc_retro').css('display', 'none'); } } else { - $('#bc_retro').css('display','none'); + $('#bc_retro').css('display', 'none'); setDateAndTime(); boluscalc.updateVisualisations(client.sbx); - if (event) { - boluscalc.calculateInsulin(); - } -// Nightscout.utils.setYAxisOffset(50); //50% of extend -// Nightscout.utils.updateBrushToTime(Nightscout.utils.mergeInputTime($('#bc_eventTimeValue').val(), $('#bc_eventDateValue').val()).toDate()); + if (event) { + boluscalc.calculateInsulin(); + } + // Nightscout.utils.setYAxisOffset(50); //50% of extend + // Nightscout.utils.updateBrushToTime(Nightscout.utils.mergeInputTime($('#bc_eventTimeValue').val(), $('#bc_eventDateValue').val()).toDate()); } maybePrevent(event); }; @@ -159,20 +158,20 @@ function init(client, $) { maybePrevent(event); }; - boluscalc.prepare = function prepare( ) { + boluscalc.prepare = function prepare () { foods = []; $('#bc_profile').empty(); var profiles = client.profilefunctions.listBasalProfiles(); - profiles.forEach(function (p) { + profiles.forEach(function(p) { $('#bc_profile').append(''); }); $('#bc_profileLabel').toggle(isProfileEnabled(profiles)); - $('#bc_usebg').prop('checked','checked'); - $('#bc_usecarbs').prop('checked','checked'); - $('#bc_usecob').prop('checked',''); - $('#bc_useiob').prop('checked','checked'); - $('#bc_bgfromsensor').prop('checked','checked'); + $('#bc_usebg').prop('checked', 'checked'); + $('#bc_usecarbs').prop('checked', 'checked'); + $('#bc_usecob').prop('checked', ''); + $('#bc_useiob').prop('checked', 'checked'); + $('#bc_bgfromsensor').prop('checked', 'checked'); $('#bc_carbs').val(''); $('#bc_quickpick').val(-1); $('#bc_preBolus').val(0); @@ -189,9 +188,9 @@ function init(client, $) { boluscalc.calculateInsulin = function calculateInsulin (event) { maybePrevent(event); - boluscalc.gatherBoluscalcData( ); + boluscalc.gatherBoluscalcData(); boluscalc.updateGui(boluscalc.record); - return boluscalc.record; + return boluscalc.record; }; boluscalc.updateGui = function updateGui (record) { @@ -236,11 +235,11 @@ function init(client, $) { $('#bc_bg').css('background-color', ''); } $('#bc_inzulinbg').text(record.insulinbg.toFixed(2)); - $('#bc_inzulinbg').attr('title', - 'Target BG range: '+targetBGLow + ' - ' + targetBGHigh + - '\nISF: ' + isf + - '\nBG diff: ' + record.bgdiff.toFixed(1) - ); + $('#bc_inzulinbg').attr('title' + , 'Target BG range: ' + targetBGLow + ' - ' + targetBGHigh + + '\nISF: ' + isf + + '\nBG diff: ' + record.bgdiff.toFixed(1) + ); } else { $('#bc_inzulinbgtd').css('background-color', ''); $('#bc_bg').css('background-color', ''); @@ -252,51 +251,51 @@ function init(client, $) { if (record.foods.length) { var html = ''; var carbs = 0; - for (var fi=0; fi'; + html += ''; } html += ''; - html += ''; - html += ''; - html += ''; + html += ''; + html += ''; + html += ''; html += ''; } html += '
'+ f.name + ''+ (f.portion*f.portions).toFixed(1) + ' ' + translate(f.unit) + '('+ (f.carbs*f.portions).toFixed(1) + ' g)' + f.name + '' + (f.portion * f.portions).toFixed(1) + ' ' + translate(f.unit) + '(' + (f.carbs * f.portions).toFixed(1) + ' g)
'; $('#bc_food').html(html); $('.deleteFoodRecord').click(deleteFoodRecord); $('#bc_carbs').val(carbs.toFixed(0)); - $('#bc_carbs').attr('disabled',true); - $('#bc_gi').css('display','none'); - $('#bc_gicalculated').css('display',''); + $('#bc_carbs').attr('disabled', true); + $('#bc_gi').css('display', 'none'); + $('#bc_gicalculated').css('display', ''); $('#bc_gicalculated').text(record.gi); } else { $('#bc_food').html(''); - $('#bc_carbs').attr('disabled',false); - $('#bc_gi').css('display',''); - $('#bc_gicalculated').css('display','none'); + $('#bc_carbs').attr('disabled', false); + $('#bc_gi').css('display', ''); + $('#bc_gicalculated').css('display', 'none'); $('#bc_gicalculated').text(''); } // Show Carbs if ($('#bc_usecarbs').is(':checked')) { if ($('#bc_carbs').val() === '') { - $('#bc_carbs').css('background-color',''); - } else if (isNaN(parseInt($('#bc_carbs').val().replace(',','.')))) { - $('#bc_carbs').css('background-color','red'); + $('#bc_carbs').css('background-color', ''); + } else if (isNaN(parseInt($('#bc_carbs').val().replace(',', '.')))) { + $('#bc_carbs').css('background-color', 'red'); } else { - $('#bc_carbs').css('background-color',''); + $('#bc_carbs').css('background-color', ''); } $('#bc_inzulincarbs').text(record.insulincarbs.toFixed(2)); - $('#bc_inzulincarbs').attr('title','IC: ' + ic); + $('#bc_inzulincarbs').attr('title', 'IC: ' + ic); } else { - $('#bc_carbs').css('background-color',''); + $('#bc_carbs').css('background-color', ''); $('#bc_inzulincarbs').text(''); - $('#bc_inzulincarbs').attr('title',''); + $('#bc_inzulincarbs').attr('title', ''); $('#bc_carbs').text(''); } @@ -309,21 +308,21 @@ function init(client, $) { if (record.othercorrection === 0 && record.carbs === 0 && record.cob === 0 && record.bg > 0 && outcome > targetBGLow && outcome < targetBGHigh) { $('#bc_carbsneeded').text(''); $('#bc_insulinover').text(''); - $('#bc_carbsneededtr').css('display','none'); - $('#bc_insulinneededtr').css('display','none'); - $('#bc_calculationintarget').css('display',''); - } else if (record.insulin<0) { - $('#bc_carbsneeded').text(record.carbsneeded+' g'); + $('#bc_carbsneededtr').css('display', 'none'); + $('#bc_insulinneededtr').css('display', 'none'); + $('#bc_calculationintarget').css('display', ''); + } else if (record.insulin < 0) { + $('#bc_carbsneeded').text(record.carbsneeded + ' g'); $('#bc_insulinover').text(record.insulin.toFixed(2)); - $('#bc_carbsneededtr').css('display',''); - $('#bc_insulinneededtr').css('display','none'); - $('#bc_calculationintarget').css('display','none'); + $('#bc_carbsneededtr').css('display', ''); + $('#bc_insulinneededtr').css('display', 'none'); + $('#bc_calculationintarget').css('display', 'none'); } else { $('#bc_carbsneeded').text(''); $('#bc_insulinover').text(''); - $('#bc_carbsneededtr').css('display','none'); - $('#bc_insulinneededtr').css('display',''); - $('#bc_calculationintarget').css('display','none'); + $('#bc_carbsneededtr').css('display', 'none'); + $('#bc_insulinneededtr').css('display', ''); + $('#bc_calculationintarget').css('display', 'none'); } // Show basal rate @@ -335,7 +334,7 @@ function init(client, $) { $('#bc_basal').text(tempMark + basal.totalbasal.toFixed(3)); }; - boluscalc.gatherBoluscalcData = function gatherBoluscalcData() { + boluscalc.gatherBoluscalcData = function gatherBoluscalcData () { boluscalc.record = {}; var record = boluscalc.record; @@ -351,7 +350,6 @@ function init(client, $) { return; } - // Calculate event time from date & time record.eventTime = new Date(); if ($('#bc_othertime').is(':checked')) { @@ -373,19 +371,19 @@ function init(client, $) { record.ic = ic; if (targetBGLow === 0 || targetBGHigh === 0 || isf === 0 || ic === 0) { - $('#bc_inzulinbgtd').css('background-color','red'); + $('#bc_inzulinbgtd').css('background-color', 'red'); boluscalc.record = {}; return; } else { - $('#bc_inzulinbgtd').css('background-color',''); + $('#bc_inzulinbgtd').css('background-color', ''); } if (ic === 0) { - $('#bc_inzulincarbstd').css('background-color','red'); + $('#bc_inzulincarbstd').css('background-color', 'red'); boluscalc.record = {}; return; } else { - $('#bc_inzulincarbstd').css('background-color',''); + $('#bc_inzulincarbstd').css('background-color', ''); } // Load IOB @@ -407,7 +405,7 @@ function init(client, $) { record.insulinbg = 0; record.bgdiff = 0; if ($('#bc_usebg').is(':checked')) { - record.bg = parseFloat($('#bc_bg').val().replace(',','.')); + record.bg = parseFloat($('#bc_bg').val().replace(',', '.')); if (isNaN(record.bg)) { record.bg = 0; } @@ -417,7 +415,7 @@ function init(client, $) { record.bgdiff = record.bg - targetBGHigh; } record.bgdiff = roundTo(record.bgdiff, 0.1); - if (record.bg !== 0){ + if (record.bg !== 0) { record.insulinbg = roundTo(record.bgdiff / isf, 0.01); } } @@ -427,7 +425,7 @@ function init(client, $) { record.foods = _.cloneDeep(foods); if (record.foods.length) { var gisum = 0; - for (var fi=0; fi= 0) { @@ -613,16 +612,16 @@ function init(client, $) { var foodlist = []; var databaseloaded = false; var filter = { - category: '' + category: '' , subcategory: '' , name: '' }; - boluscalc.loadFoodDatabase = function loadFoodDatabase(event, callback) { + boluscalc.loadFoodDatabase = function loadFoodDatabase (event, callback) { categories = []; foodlist = []; var records = client.sbx.data.food || []; - records.forEach(function (r) { + records.forEach(function(r) { if (r.type == 'food') { foodlist.push(r); if (r.category && !categories[r.category]) { @@ -640,77 +639,77 @@ function init(client, $) { if (callback) { callback(); } }; - boluscalc.loadFoodQuickpicks = function loadFoodQuickpicks( ) { + boluscalc.loadFoodQuickpicks = function loadFoodQuickpicks () { // Load quickpicks quickpicks = []; var records = client.sbx.data.food || []; - records.forEach(function (r) { + records.forEach(function(r) { if (r.type == 'quickpick') { quickpicks.push(r); } }); $('#bc_quickpick').empty().append(''); - for (var i=0; i' + r.name + ' (' + r.carbs + ' g)'); - }; + $('#bc_quickpick').append(''); + } $('#bc_quickpick').val(-1); $('#bc_quickpick').change(quickpickChange); }; - function fillForm(event) { + function fillForm (event) { $('#bc_filter_category').empty().append(''); - Object.keys(categories).forEach( function eachCategory(s) { - $('#bc_filter_category').append(''); + Object.keys(categories).forEach(function eachCategory (s) { + $('#bc_filter_category').append(''); }); filter.category = ''; fillSubcategories(); $('#bc_filter_category').change(fillSubcategories); $('#bc_filter_subcategory').change(doFilter); - $('#bc_filter_name').on('input',doFilter); + $('#bc_filter_name').on('input', doFilter); maybePrevent(event); return false; } - function fillSubcategories(event) { + function fillSubcategories (event) { maybePrevent(event); filter.category = $('#bc_filter_category').val(); filter.subcategory = ''; $('#bc_filter_subcategory').empty().append(''); if (filter.category !== '') { - Object.keys(categories[filter.category]).forEach( function eachSubcategory(s) { - $('#bc_filter_subcategory').append(''); + Object.keys(categories[filter.category]).forEach(function eachSubcategory (s) { + $('#bc_filter_subcategory').append(''); }); } doFilter(); } - function doFilter(event) { + function doFilter (event) { if (event) { filter.category = $('#bc_filter_category').val(); filter.subcategory = $('#bc_filter_subcategory').val(); filter.name = $('#bc_filter_name').val(); } $('#bc_data').empty(); - for (var i=0; i' + o + ''); + o += 'Carbs: ' + foodlist[i].carbs + ' g'; + $('#bc_data').append(''); } $('#bc_addportions').val('1'); maybePrevent(event); } - function addFoodFromDatabase(event) { + function addFoodFromDatabase (event) { if (!databaseloaded) { boluscalc.loadFoodDatabase(event, addFoodFromDatabase); return; @@ -718,30 +717,32 @@ function init(client, $) { $('#bc_addportions').val('1'); $('#bc_addfooddialog').dialog({ - width: 640 + width: 640 , height: 400 - , buttons: [ - { text: translate('Add'), - click: function() { - var index = $('#bc_data').val(); - var portions = parseFloat($('#bc_addportions').val().replace(',','.')); - if (index !== null && !isNaN(portions) && portions >0) { - foodlist[index].portions = portions; - foods.push(_.cloneDeep(foodlist[index])); - $( this ).dialog( 'close' ); - boluscalc.calculateInsulin(); + , buttons: [ + { + text: translate('Add') + , click: function() { + var index = $('#bc_data').val(); + var portions = parseFloat($('#bc_addportions').val().replace(',', '.')); + if (index !== null && !isNaN(portions) && portions > 0) { + foodlist[index].portions = portions; + foods.push(_.cloneDeep(foodlist[index])); + $(this).dialog('close'); + boluscalc.calculateInsulin(); + } } - } - }, - { text: translate('Reload database'), - class: 'leftButton', - click: boluscalc.loadFoodDatabase + } + , { + text: translate('Reload database') + , class: 'leftButton' + , click: boluscalc.loadFoodDatabase } ] - , open : function() { + , open: function() { $(this).parent().css('box-shadow', '20px 20px 20px 0px black'); - $(this).parent().find('.ui-dialog-buttonset' ).css({'width':'100%','text-align':'right'}); - $(this).parent().find('button:contains("'+translate('Add')+'")').css({'float':'left'}); + $(this).parent().find('.ui-dialog-buttonset').css({ 'width': '100%', 'text-align': 'right' }); + $(this).parent().find('button:contains("' + translate('Add') + '")').css({ 'float': 'left' }); $('#bc_filter_name').focus(); } @@ -750,7 +751,7 @@ function init(client, $) { return false; } - function findClosestSGVToPastTime(time) { + function findClosestSGVToPastTime (time) { var nowData = client.entries.filter(function(d) { return d.type === 'sgv' && d.mills <= time.getTime(); }); @@ -766,12 +767,12 @@ function init(client, $) { // Make it faster on mobile devices $('.insulincalculationpart').change(boluscalc.calculateInsulin); } else { - $('.insulincalculationpart').on('input',boluscalc.calculateInsulin); + $('.insulincalculationpart').on('input', boluscalc.calculateInsulin); $('input:checkbox.insulincalculationpart').change(boluscalc.calculateInsulin); } $('#bc_bgfrommeter').change(boluscalc.calculateInsulin); $('#bc_addfromdatabase').click(addFoodFromDatabase); - $('#bc_bgfromsensor').change(function bc_bgfromsensor_click(event) { + $('#bc_bgfromsensor').change(function bc_bgfromsensor_click (event) { boluscalc.updateVisualisations(client.sbx); boluscalc.calculateInsulin(); maybePrevent(event); diff --git a/lib/client/browser-settings.js b/lib/client/browser-settings.js index bfac4df8..05ffed1b 100644 --- a/lib/client/browser-settings.js +++ b/lib/client/browser-settings.js @@ -8,18 +8,18 @@ var Storages = require('js-storage'); function init (client, serverSettings, $) { - serverSettings = serverSettings || {settings: {}}; + serverSettings = serverSettings || { settings: {} }; var storage = Storages.localStorage; var settings = require('../settings')(); - function loadForm ( ) { + function loadForm () { var utils = client.utils; var language = require('../language')(); language.set(settings.language); var translate = language.translate; - function appendThresholdValue(threshold) { + function appendThresholdValue (threshold) { return settings.alarmTypes.indexOf('simple') === -1 ? '' : ' (' + utils.scaleMgdl(threshold) + ')'; } @@ -61,8 +61,8 @@ function init (client, serverSettings, $) { var langSelect = $('#language'); - _.each(language.languages, function eachLanguage(lang) { - langSelect.append(''); + _.each(language.languages, function eachLanguage (lang) { + langSelect.append(''); }); langSelect.val(settings.language); @@ -79,7 +79,7 @@ function init (client, serverSettings, $) { var showPluginsSettings = $('#show-plugins'); var hasPluginsToShow = false; - client.plugins.eachEnabledPlugin(function each(plugin) { + client.plugins.eachEnabledPlugin(function each (plugin) { if (client.plugins.specialPlugins.indexOf(plugin.name) > -1) { //ignore these, they are always on for now } else { @@ -97,7 +97,7 @@ function init (client, serverSettings, $) { } - function wireForm ( ) { + function wireForm () { $('#useDefaults').click(function(event) { settings.eachSetting(function clearEachSetting (name) { storage.remove(name); @@ -108,43 +108,41 @@ function init (client, serverSettings, $) { }); $('#save').click(function(event) { - function checkedPluginNames() { + function checkedPluginNames () { var checkedPlugins = []; - $('#show-plugins input:checked').each(function eachPluginCheckbox(index, checkbox) { + $('#show-plugins input:checked').each(function eachPluginCheckbox (index, checkbox) { checkedPlugins.push($(checkbox).val()); }); return checkedPlugins.join(' '); } - function storeInBrowser(data) { - for (var k in data) { - if (data.hasOwnProperty(k)) { - storage.set(k, data[k]); - } - } + function storeInBrowser (data) { + Object.keys(data).forEach(k => { + storage.set(k, data[k]); + }); } storeInBrowser({ - units: $('input:radio[name=units-browser]:checked').val(), - alarmUrgentHigh: $('#alarm-urgenthigh-browser').prop('checked'), - alarmHigh: $('#alarm-high-browser').prop('checked'), - alarmLow: $('#alarm-low-browser').prop('checked'), - alarmUrgentLow: $('#alarm-urgentlow-browser').prop('checked'), - alarmTimeagoWarn: $('#alarm-timeagowarn-browser').prop('checked'), - alarmTimeagoWarnMins: parseInt($('#alarm-timeagowarnmins-browser').val()) || 15, - alarmTimeagoUrgent: $('#alarm-timeagourgent-browser').prop('checked'), - alarmTimeagoUrgentMins: parseInt($('#alarm-timeagourgentmins-browser').val()) || 30, - nightMode: $('#nightmode-browser').prop('checked'), - editMode: $('#editmode-browser').prop('checked'), - showRawbg: $('input:radio[name=show-rawbg]:checked').val(), - customTitle: $('input#customTitle').prop('value'), - theme: $('input:radio[name=theme-browser]:checked').val(), - timeFormat: parseInt($('input:radio[name=timeformat-browser]:checked').val()), - language: $('#language').val(), - scaleY: $('#scaleY').val(), - basalrender: $('#basalrender').val(), - showPlugins: checkedPluginNames(), - storageVersion: STORAGE_VERSION + units: $('input:radio[name=units-browser]:checked').val() + , alarmUrgentHigh: $('#alarm-urgenthigh-browser').prop('checked') + , alarmHigh: $('#alarm-high-browser').prop('checked') + , alarmLow: $('#alarm-low-browser').prop('checked') + , alarmUrgentLow: $('#alarm-urgentlow-browser').prop('checked') + , alarmTimeagoWarn: $('#alarm-timeagowarn-browser').prop('checked') + , alarmTimeagoWarnMins: parseInt($('#alarm-timeagowarnmins-browser').val()) || 15 + , alarmTimeagoUrgent: $('#alarm-timeagourgent-browser').prop('checked') + , alarmTimeagoUrgentMins: parseInt($('#alarm-timeagourgentmins-browser').val()) || 30 + , nightMode: $('#nightmode-browser').prop('checked') + , editMode: $('#editmode-browser').prop('checked') + , showRawbg: $('input:radio[name=show-rawbg]:checked').val() + , customTitle: $('input#customTitle').prop('value') + , theme: $('input:radio[name=theme-browser]:checked').val() + , timeFormat: parseInt($('input:radio[name=timeformat-browser]:checked').val()) + , language: $('#language').val() + , scaleY: $('#scaleY').val() + , basalrender: $('#basalrender').val() + , showPlugins: checkedPluginNames() + , storageVersion: STORAGE_VERSION }); event.preventDefault(); @@ -152,13 +150,13 @@ function init (client, serverSettings, $) { }); } - function showLocalstorageError ( ) { + function showLocalstorageError () { var msg = 'Settings are disabled.

Please enable cookies so you may customize your Nightscout site.'; - $('.browserSettings').html('Settings'+msg+''); + $('.browserSettings').html('Settings' + msg + ''); $('#save').hide(); } - function handleStorageVersions ( ) { + function handleStorageVersions () { var previousVersion = parseInt(storage.get('storageVersion')); //un-versioned settings @@ -174,7 +172,7 @@ function init (client, serverSettings, $) { } } - settings.extendedSettings = serverSettings.extendedSettings || {settings: {}}; + settings.extendedSettings = serverSettings.extendedSettings || { settings: {} }; try { settings.eachSetting(function setEach (name) { @@ -200,12 +198,12 @@ function init (client, serverSettings, $) { var stored = storage.get('basalrender'); settings.extendedSettings.basal.render = stored !== null ? stored : settings.extendedSettings.basal.render; - } catch(err) { + } catch (err) { console.error(err); showLocalstorageError(); } - init.loadAndWireForm = function loadAndWireForm ( ) { + init.loadAndWireForm = function loadAndWireForm () { loadForm(); wireForm(); }; @@ -213,5 +211,4 @@ function init (client, serverSettings, $) { return settings; } - module.exports = init; diff --git a/lib/client/browser-utils.js b/lib/client/browser-utils.js index fc9a983d..4f920588 100644 --- a/lib/client/browser-utils.js +++ b/lib/client/browser-utils.js @@ -13,9 +13,9 @@ function init ($) { $('#drawer').find('.tip').tooltip(); } $.fn.tooltip.defaults = { - fade: true, - gravity: 'n', - opacity: 0.75 + fade: true + , gravity: 'n' + , opacity: 0.75 }; var querystring = queryParms(); @@ -38,31 +38,30 @@ function init ($) { event.preventDefault(); }); - $('.navigation a').click(function navigationClick ( ) { + $('.navigation a').click(function navigationClick () { closeDrawer('#drawer'); }); - function reload() { + function reload () { //strip '#' so form submission does not fail var url = window.location.href; url = url.replace(/#$/, ''); window.location.href = url; } - - function queryParms() { + function queryParms () { var params = {}; if (location.search) { location.search.substr(1).split('&').forEach(function(item) { + // eslint-disable-next-line no-useless-escape params[item.split('=')[0]] = item.split('=')[1].replace(/[_\+]/g, ' '); }); } return params; } - function isTouch() { - try { document.createEvent('TouchEvent'); return true; } - catch (e) { return false; } + function isTouch () { + try { document.createEvent('TouchEvent'); return true; } catch (e) { return false; } } function closeLastOpenedDrawer (callback) { @@ -73,15 +72,15 @@ function init ($) { } } - function closeDrawer(id, callback) { + function closeDrawer (id, callback) { lastOpenedDrawer = null; $('html, body').css({ scrollTop: 0 }); - $(id).css({display: 'none', right: '-300px'}); + $(id).css({ display: 'none', right: '-300px' }); if (callback) { callback(); } } - function openDrawer(id, prepare) { - function closeOpenDraw(callback) { + function openDrawer (id, prepare) { + function closeOpenDraw (callback) { if (lastOpenedDrawer) { closeDrawer(lastOpenedDrawer, callback); } else { @@ -89,11 +88,11 @@ function init ($) { } } - closeOpenDraw(function () { + closeOpenDraw(function() { lastOpenedDrawer = id; if (prepare) { prepare(); } - var style = {display:'block', right: '0'}; + var style = { display: 'block', right: '0' }; var windowWidth = $(window).width(); var windowHeight = $(window).height(); @@ -114,13 +113,12 @@ function init ($) { style.width = '350px'; } - $(id).css(style); }); } - function toggleDrawer(id, openPrepare, closeCallback) { + function toggleDrawer (id, openPrepare, closeCallback) { if (lastOpenedDrawer === id) { closeDrawer(id, closeCallback); } else { @@ -128,13 +126,13 @@ function init ($) { } } - function closeNotification() { + function closeNotification () { var notify = $('#notification'); notify.hide(); notify.find('span').html(''); } - function showNotification(note, type) { + function showNotification (note, type) { var notify = $('#notification'); notify.hide(); @@ -150,10 +148,10 @@ function init ($) { notify.show(); } - function getLastOpenedDrawer() { + function getLastOpenedDrawer () { return lastOpenedDrawer; } - + return { reload: reload , queryParms: queryParms diff --git a/lib/client/clock-client.js b/lib/client/clock-client.js index df4c8092..ee067086 100644 --- a/lib/client/clock-client.js +++ b/lib/client/clock-client.js @@ -9,14 +9,14 @@ client.settings = browserSettings(client, window.serverSettings, $); // console.log('settings', client.settings); // client.settings now contains all settings -client.query = function query() { +client.query = function query () { console.log('query'); $.ajax('/api/v1/entries.json?count=3', { success: client.render }); } -client.render = function render(xhr) { +client.render = function render (xhr) { console.log('got data', xhr); let rec; @@ -33,9 +33,9 @@ client.render = function render(xhr) { // Convert BG to mmol/L if necessary. if (window.serverSettings.settings.units == 'mmol') { - var displayValue = Nightscout.units.mgdlToMMOL(rec.sgv); + var displayValue = window.Nightscout.units.mgdlToMMOL(rec.sgv); } else { - var displayValue = rec.sgv; + displayValue = rec.sgv; } // Insert the BG value text. @@ -53,8 +53,8 @@ client.render = function render(xhr) { // Generate and insert the clock. let timeDivisor = (client.settings.timeFormat) ? client.settings.timeFormat : 12; - let today = new Date(), - h = today.getHours() % timeDivisor; + let today = new Date() + , h = today.getHours() % timeDivisor; if (timeDivisor == 12) { h = (h == 0) ? 12 : h; // In the case of 00:xx, change to 12:xx for 12h time } @@ -65,6 +65,8 @@ client.render = function render(xhr) { if (m < 10) m = "0" + m; $('#clock').text(h + ":" + m); + // defined in the template this is loaded into + // eslint-disable-next-line no-undef if (clockFace == 'clock-color') { var bgHigh = window.serverSettings.settings.thresholds.bgHigh; @@ -115,10 +117,10 @@ client.render = function render(xhr) { } } -client.init = function init() { +client.init = function init () { console.log('init'); client.query(); setInterval(client.query, 1 * 60 * 1000); } -module.exports = client; \ No newline at end of file +module.exports = client; diff --git a/lib/client/index.js b/lib/client/index.js index 5d8eecdb..311a49ce 100644 --- a/lib/client/index.js +++ b/lib/client/index.js @@ -16,13 +16,13 @@ var levels = require('../levels'); var times = require('../times'); var receiveDData = require('./receiveddata'); -var client = { }; +var client = {}; $('#loadingMessageText').html('Connecting to server'); client.hashauth = require('../hashauth').init(client, $); -client.headers = function headers ( ) { +client.headers = function headers () { if (client.authorized) { return { Authorization: 'Bearer ' + client.authorized.token @@ -32,11 +32,11 @@ client.headers = function headers ( ) { 'api-secret': client.hashauth.hash() }; } else { - return { }; + return {}; } }; -client.init = function init(callback) { +client.init = function init (callback) { client.browserUtils = require('./browser-utils')($); @@ -60,16 +60,17 @@ client.init = function init(callback) { console.log('Application appears to be online'); $('#centerMessagePanel').hide(); client.load(serverSettings, callback); - }).fail(function fail(jqXHR, textStatus, errorThrown) { + // eslint-disable-next-line no-unused-vars + }).fail(function fail (jqXHR, textStatus, errorThrown) { - // check if we couldn't reach the server at all, show offline message - if (jqXHR.readyState == 0) { + // check if we couldn't reach the server at all, show offline message + if (jqXHR.readyState == 0) { console.log('Application appears to be OFFLINE'); $('#loadingMessageText').html('Connecting to Nightscout server failed, retrying every 2 seconds'); window.setTimeout(window.Nightscout.client.init(), 2000); return; - } - + } + //no server setting available, use defaults, auth, etc if (client.settingsFailed) { console.log('Already tried to get settings after auth, but failed'); @@ -77,9 +78,9 @@ client.init = function init(callback) { client.settingsFailed = true; language.set('en'); client.translate = language.translate; - // auth failed, hide loader and request for key - $('#centerMessagePanel').hide(); - client.hashauth.requestAuthentication(function afterRequest ( ) { + // auth failed, hide loader and request for key + $('#centerMessagePanel').hide(); + client.hashauth.requestAuthentication(function afterRequest () { client.init(null, callback); }); } @@ -87,23 +88,21 @@ client.init = function init(callback) { }; -client.load = function load(serverSettings, callback) { +client.load = function load (serverSettings, callback) { var UPDATE_TRANS_MS = 750 // milliseconds , FORMAT_TIME_12 = '%-I:%M %p' , FORMAT_TIME_12_COMPACT = '%-I:%M' , FORMAT_TIME_24 = '%H:%M%' , FORMAT_TIME_12_SCALE = '%-I %p' - , FORMAT_TIME_24_SCALE = '%H' - ; + , FORMAT_TIME_24_SCALE = '%H'; var history = 48; - + var chart , socket , isInitialData = false - , prevSGV - , opacity = {current: 1, DAY: 1, NIGHT: 0.5} + , opacity = { current: 1, DAY: 1, NIGHT: 0.5 } , clientAlarms = {} , alarmInProgress = false , alarmMessage @@ -111,8 +110,7 @@ client.load = function load(serverSettings, callback) { , currentAnnouncement , alarmSound = 'alarm.mp3' , urgentAlarmSound = 'alarm2.mp3' - , previousNotifyTimestamp - ; + , previousNotifyTimestamp; client.entryToDate = function entryToDate (entry) { return new Date(entry.mills); }; @@ -130,8 +128,7 @@ client.load = function load(serverSettings, callback) { , minorPills = $('.bgStatus .minorPills') , statusPills = $('.status .statusPills') , primary = $('.primary') - , editButton = $('#editbutton') - ; + , editButton = $('#editbutton'); client.tooltip = d3.select('body').append('div') .attr('class', 'tooltip') @@ -236,7 +233,7 @@ client.load = function load(serverSettings, callback) { client.boluscalc = require('./boluscalc')(client, $); client.profilefunctions = profile; - + client.editMode = false; //TODO: use the bus for updates and notifications @@ -248,13 +245,13 @@ client.load = function load(serverSettings, callback) { //start the bus after setting up listeners //client.ctx.bus.uptime( ); - client.dataExtent = function dataExtent ( ) { + client.dataExtent = function dataExtent () { return client.entries.length > 0 ? - d3.extent(client.entries, client.entryToDate) - : d3.extent([new Date(client.now - times.hours(history).msecs), new Date(client.now)]); + d3.extent(client.entries, client.entryToDate) : + d3.extent([new Date(client.now - times.hours(history).msecs), new Date(client.now)]); }; - client.bottomOfPills = function bottomOfPills ( ) { + client.bottomOfPills = function bottomOfPills () { //the offset's might not exist for some tests var bottomOfPrimary = primary.offset() ? primary.offset().top + primary.height() : 0; var bottomOfMinorPills = minorPills.offset() ? minorPills.offset().top + minorPills.height() : 0; @@ -262,7 +259,7 @@ client.load = function load(serverSettings, callback) { return Math.max(bottomOfPrimary, bottomOfMinorPills, bottomOfStatusPills); }; - function formatTime(time, compact) { + function formatTime (time, compact) { var timeFormat = getTimeFormat(false, compact); time = d3.time.format(timeFormat)(time); if (client.settings.timeFormat !== 24) { @@ -271,7 +268,7 @@ client.load = function load(serverSettings, callback) { return time; } - function getTimeFormat(isForScale, compact) { + function getTimeFormat (isForScale, compact) { var timeFormat = FORMAT_TIME_12; if (client.settings.timeFormat === 24) { timeFormat = isForScale ? FORMAT_TIME_24_SCALE : FORMAT_TIME_24; @@ -283,7 +280,7 @@ client.load = function load(serverSettings, callback) { } //TODO: replace with utils.scaleMgdl and/or utils.roundBGForDisplay - function scaleBg(bg) { + function scaleBg (bg) { if (client.settings.units === 'mmol') { return units.mgdlToMMOL(bg); } else { @@ -291,8 +288,8 @@ client.load = function load(serverSettings, callback) { } } - function generateTitle ( ) { - function s(value, sep) { return value ? value + ' ' : sep || ''; } + function generateTitle () { + function s (value, sep) { return value ? value + ' ' : sep || ''; } var title = ''; @@ -300,7 +297,7 @@ client.load = function load(serverSettings, callback) { if (status !== 'current') { var ago = client.timeago.calcDisplay(client.sbx.lastSGVEntry(), client.sbx.time); - title = s(ago.value) + s(ago.label, ' - ') + title; + title = s(ago.value) + s(ago.label, ' - ') + title; } else if (client.latestSGV) { var currentMgdl = client.latestSGV.mgdl; @@ -317,12 +314,12 @@ client.load = function load(serverSettings, callback) { return title; } - function resetCustomTitle ( ) { + function resetCustomTitle () { var customTitle = client.settings.customTitle || 'Nightscout'; $('.customTitle').text(customTitle); } - function checkAnnouncement() { + function checkAnnouncement () { var result = { inProgress: currentAnnouncement ? Date.now() - currentAnnouncement.received < times.mins(5).msecs : false }; @@ -339,19 +336,19 @@ client.load = function load(serverSettings, callback) { return result; } - function updateTitle ( ) { + function updateTitle () { var windowTitle; var announcementStatus = checkAnnouncement(); if (alarmMessage && alarmInProgress) { $('.customTitle').text(alarmMessage); - if (!isTimeAgoAlarmType( )) { + if (!isTimeAgoAlarmType()) { windowTitle = alarmMessage + ': ' + generateTitle(); } } else if (announcementStatus.inProgress && announcementStatus.message) { windowTitle = announcementStatus.message + ': ' + generateTitle(); - } else { + } else { resetCustomTitle(); } @@ -360,8 +357,8 @@ client.load = function load(serverSettings, callback) { $(document).attr('title', windowTitle || generateTitle()); } -// clears the current user brush and resets to the current real time data - function updateBrushToNow(skipBrushing) { + // clears the current user brush and resets to the current real time data + function updateBrushToNow (skipBrushing) { // get current time range var dataRange = client.dataExtent(); @@ -377,15 +374,15 @@ client.load = function load(serverSettings, callback) { } } - function alarmingNow() { + function alarmingNow () { return container.hasClass('alarming'); } - function inRetroMode() { + function inRetroMode () { return chart && chart.inRetroMode(); } - function brushed ( ) { + function brushed () { var brushExtent = chart.brush.extent(); @@ -403,7 +400,7 @@ client.load = function load(serverSettings, callback) { } } - function adjustCurrentSGVClasses(value, isCurrent) { + function adjustCurrentSGVClasses (value, isCurrent) { var reallyCurrentAndNotAlarming = isCurrent && !inRetroMode() && !alarmingNow(); bgStatus.toggleClass('current', alarmingNow() || reallyCurrentAndNotAlarming); @@ -469,7 +466,7 @@ client.load = function load(serverSettings, callback) { forecastOption.append(forecastLabel); forecastLabel.append(forecastCheckbox); forecastLabel.append('Show ' + info.label + ''); - forecastCheckbox.change(function onChange(event) { + forecastCheckbox.change(function onChange (event) { var checkbox = $(event.target); var type = checkbox.attr('data-forecast-type'); var checked = checkbox.prop('checked'); @@ -477,7 +474,7 @@ client.load = function load(serverSettings, callback) { client.settings.showForecast += ' ' + type; } else { client.settings.showForecast = _.chain(client.settings.showForecast.split(' ')) - .filter(function (forecast) { return forecast !== type; }) + .filter(function(forecast) { return forecast !== type; }) .value() .join(' '); } @@ -491,7 +488,7 @@ client.load = function load(serverSettings, callback) { client.boluscalc.updateVisualisations(client.sbx); } - function clearCurrentSGV ( ) { + function clearCurrentSGV () { currentBG.text('---'); container.removeClass('urgent warning inrange'); } @@ -502,7 +499,7 @@ client.load = function load(serverSettings, callback) { }); var focusPoint = _.last(nowData); - function updateHeader() { + function updateHeader () { if (inRetroMode()) { nowDate = brushExtent[1]; $('#currentTime') @@ -533,10 +530,10 @@ client.load = function load(serverSettings, callback) { } var top = (client.bottomOfPills() + 5); - $('#chartContainer').css({top: top + 'px', height: $(window).height() - top - 10}); + $('#chartContainer').css({ top: top + 'px', height: $(window).height() - top - 10 }); } - function sgvToColor(sgv) { + function sgvToColor (sgv) { var color = 'grey'; if (client.settings.theme !== 'default') { @@ -556,7 +553,7 @@ client.load = function load(serverSettings, callback) { return color; } - function sgvToColoredRange(sgv) { + function sgvToColoredRange (sgv) { var range = ''; if (client.settings.theme !== 'default') { @@ -576,7 +573,7 @@ client.load = function load(serverSettings, callback) { return range; } - function formatAlarmMessage(notify) { + function formatAlarmMessage (notify) { var announcementMessage = notify && notify.isAnnouncement && notify.message && notify.message.length > 1; if (announcementMessage) { @@ -584,7 +581,7 @@ client.load = function load(serverSettings, callback) { } else if (notify) { return notify.title; } - return null; + return null; } function setAlarmMessage (notify) { @@ -599,7 +596,7 @@ client.load = function load(serverSettings, callback) { var selector = '.audio.alarms audio.' + file; if (!alarmingNow()) { - d3.select(selector).each(function () { + d3.select(selector).each(function() { var audio = this; playAlarm(audio); $(this).addClass('playing'); @@ -628,7 +625,7 @@ client.load = function load(serverSettings, callback) { event.preventDefault(); } - function playAlarm(audio) { + function playAlarm (audio) { // ?mute=true disables alarms to testers. if (client.browserUtils.queryParms().mute !== 'true') { audio.play(); @@ -637,11 +634,11 @@ client.load = function load(serverSettings, callback) { } } - function stopAlarm(isClient, silenceTime, notify) { + function stopAlarm (isClient, silenceTime, notify) { alarmInProgress = false; alarmMessage = null; container.removeClass('urgent warning'); - d3.selectAll('audio.playing').each(function () { + d3.selectAll('audio.playing').each(function() { var audio = this; audio.pause(); $(this).removeClass('playing'); @@ -688,7 +685,7 @@ client.load = function load(serverSettings, callback) { brushed(); } - function refreshAuthIfNeeded ( ) { + function refreshAuthIfNeeded () { var token = client.browserUtils.queryParms().token; if (token && client.authorized) { var renewTime = (client.authorized.exp * 1000) - times.mins(15).msecs - Math.abs((client.authorized.iat * 1000) - client.authorized.lat); @@ -696,7 +693,7 @@ client.load = function load(serverSettings, callback) { if (client.now > renewTime) { console.info('Refreshing authorization'); $.ajax('/api/v2/authorization/request/' + token, { - success: function (authorized) { + success: function(authorized) { if (authorized) { console.info('Got new authorization', authorized); authorized.lat = client.now; @@ -710,10 +707,10 @@ client.load = function load(serverSettings, callback) { } } - function updateClock() { + function updateClock () { updateClockDisplay(); var interval = (60 - (new Date()).getSeconds()) * 1000 + 5; - setTimeout(updateClock,interval); + setTimeout(updateClock, interval); updateTimeAgo(); if (chart) { @@ -735,7 +732,7 @@ client.load = function load(serverSettings, callback) { } } - function updateClockDisplay() { + function updateClockDisplay () { if (inRetroMode()) { return; } @@ -743,7 +740,7 @@ client.load = function load(serverSettings, callback) { $('#currentTime').text(formatTime(new Date(client.now), true)).css('text-decoration', ''); } - function getClientAlarm(level, group) { + function getClientAlarm (level, group) { var key = level + '-' + group; var alarm = clientAlarms[key]; if (!alarm) { @@ -753,13 +750,13 @@ client.load = function load(serverSettings, callback) { return alarm; } - function isTimeAgoAlarmType() { + function isTimeAgoAlarmType () { return currentNotify && currentNotify.group === 'Time Ago'; } function isStale (status) { - return client.settings.alarmTimeagoWarn && status === 'warn' - || client.settings.alarmTimeagoUrgent && status === 'urgent'; + return client.settings.alarmTimeagoWarn && status === 'warn' || + client.settings.alarmTimeagoUrgent && status === 'urgent'; } function notAcked (alarm) { @@ -786,12 +783,12 @@ client.load = function load(serverSettings, callback) { container.toggleClass('alarming-timeago', status !== 'current'); - if (alarmingNow() && status === 'current' && isTimeAgoAlarmType( )) { + if (alarmingNow() && status === 'current' && isTimeAgoAlarmType()) { stopAlarm(true, times.min().msecs); } } - function updateTimeAgo() { + function updateTimeAgo () { var status = client.timeago.checkStatus(client.sbx); if (status !== 'current') { updateTitle(); @@ -799,20 +796,20 @@ client.load = function load(serverSettings, callback) { checkTimeAgoAlarm(status); } - function updateTimeAgoSoon() { - setTimeout(function updatingTimeAgoNow() { + function updateTimeAgoSoon () { + setTimeout(function updatingTimeAgoNow () { updateTimeAgo(); }, times.secs(10).msecs); } - function refreshChart(updateToNow) { + function refreshChart (updateToNow) { if (updateToNow) { updateBrushToNow(); } chart.update(false); } - (function watchVisibility ( ) { + (function watchVisibility () { // Set the name of the hidden property and the change event for visibility var hidden, visibilityChange; if (typeof document.hidden !== 'undefined') { @@ -829,7 +826,7 @@ client.load = function load(serverSettings, callback) { visibilityChange = 'webkitvisibilitychange'; } - document.addEventListener(visibilityChange, function visibilityChanged ( ) { + document.addEventListener(visibilityChange, function visibilityChanged () { var prevHidden = client.documentHidden; client.documentHidden = document[hidden]; @@ -845,7 +842,7 @@ client.load = function load(serverSettings, callback) { updateClock(); updateTimeAgoSoon(); - function Dropdown(el) { + function Dropdown (el) { this.ddmenuitem = 0; this.$el = $(el); @@ -853,13 +850,13 @@ client.load = function load(serverSettings, callback) { $(document).click(function() { that.close(); }); } - Dropdown.prototype.close = function () { + Dropdown.prototype.close = function() { if (this.ddmenuitem) { this.ddmenuitem.css('visibility', 'hidden'); this.ddmenuitem = 0; } }; - Dropdown.prototype.open = function (e) { + Dropdown.prototype.open = function(e) { this.close(); this.ddmenuitem = $(this.$el).css('visibility', 'visible'); e.stopPropagation(); @@ -868,7 +865,7 @@ client.load = function load(serverSettings, callback) { var silenceDropdown = new Dropdown('#silenceBtn'); var viewDropdown = new Dropdown('#viewMenu'); - $('.bgButton').click(function (e) { + $('.bgButton').click(function(e) { if (alarmingNow()) { silenceDropdown.open(e); } @@ -887,23 +884,23 @@ client.load = function load(serverSettings, callback) { viewDropdown.open(e); } }); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Client-side code to connect to server and handle incoming data //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // eslint-disable-next-line no-undef client.socket = socket = io.connect(); socket.on('dataUpdate', dataUpdate); - function resetRetro ( ) { + function resetRetro () { client.retro = { loadedMills: 0 , loadStartedMills: 0 }; } - client.resetRetroIfNeeded = function resetRetroIfNeeded ( ) { + client.resetRetroIfNeeded = function resetRetroIfNeeded () { if (client.retro.loadedMills > 0 && Date.now() - client.retro.loadedMills > times.mins(5).msecs) { resetRetro(); console.info('Cleared retro data to free memory'); @@ -912,7 +909,7 @@ client.load = function load(serverSettings, callback) { resetRetro(); - client.loadRetroIfNeeded = function loadRetroIfNeeded ( ) { + client.loadRetroIfNeeded = function loadRetroIfNeeded () { var now = Date.now(); if (now - client.retro.loadStartedMills < times.secs(30).msecs) { console.info('retro already loading, started', new Date(client.retro.loadStartedMills)); @@ -940,7 +937,7 @@ client.load = function load(serverSettings, callback) { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Alarms and Text handling //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - socket.on('connect', function () { + socket.on('connect', function() { console.log('Client connected to server.'); socket.emit( 'authorize' @@ -950,10 +947,10 @@ client.load = function load(serverSettings, callback) { , token: client.authorized && client.authorized.token , history: history } - , function authCallback(data) { - console.log('Client rights: ',data); + , function authCallback (data) { + console.log('Client rights: ', data); if (!data.read || !hasRequiredPermission()) { - client.hashauth.requestAuthentication(function afterRequest ( ) { + client.hashauth.requestAuthentication(function afterRequest () { client.hashauth.updateSocketAuth(); if (callback) { callback(); @@ -966,7 +963,7 @@ client.load = function load(serverSettings, callback) { ); }); - function hasRequiredPermission ( ) { + function hasRequiredPermission () { if (client.requiredPermission) { if (client.hashauth && client.hashauth.isAuthenticated()) { return true; @@ -980,39 +977,38 @@ client.load = function load(serverSettings, callback) { //with predicted alarms, latestSGV may still be in target so to see if the alarm // is for a HIGH we can only check if it's >= the bottom of the target - function isAlarmForHigh() { + function isAlarmForHigh () { return client.latestSGV && client.latestSGV.mgdl >= client.settings.thresholds.bgTargetBottom; } //with predicted alarms, latestSGV may still be in target so to see if the alarm // is for a LOW we can only check if it's <= the top of the target - function isAlarmForLow() { + function isAlarmForLow () { return client.latestSGV && client.latestSGV.mgdl <= client.settings.thresholds.bgTargetTop; } - socket.on('notification', function (notify) { - console.log('notification from server:',notify); - - if (notify.timestamp && previousNotifyTimestamp != notify.timestamp) - { - previousNotifyTimestamp = notify.timestamp; + socket.on('notification', function(notify) { + console.log('notification from server:', notify); + + if (notify.timestamp && previousNotifyTimestamp != notify.timestamp) { + previousNotifyTimestamp = notify.timestamp; client.plugins.visualizeAlarm(client.sbx, notify, notify.title + ' ' + notify.message); } else { console.log('No timestamp found for notify, not passing to plugins'); } }); - socket.on('announcement', function (notify) { + socket.on('announcement', function(notify) { console.info('announcement received from server'); - console.log('notify:',notify); + console.log('notify:', notify); currentAnnouncement = notify; currentAnnouncement.received = Date.now(); updateTitle(); }); - socket.on('alarm', function (notify) { + socket.on('alarm', function(notify) { console.info('alarm received from server'); - console.log('notify:',notify); + console.log('notify:', notify); var enabled = (isAlarmForHigh() && client.settings.alarmHigh) || (isAlarmForLow() && client.settings.alarmLow); if (enabled) { console.log('Alarm raised!'); @@ -1023,9 +1019,9 @@ client.load = function load(serverSettings, callback) { chart.update(false); }); - socket.on('urgent_alarm', function (notify) { + socket.on('urgent_alarm', function(notify) { console.info('urgent alarm received from server'); - console.log('notify:',notify); + console.log('notify:', notify); var enabled = (isAlarmForHigh() && client.settings.alarmUrgentHigh) || (isAlarmForLow() && client.settings.alarmUrgentLow); if (enabled) { @@ -1037,7 +1033,7 @@ client.load = function load(serverSettings, callback) { chart.update(false); }); - socket.on('clear_alarm', function (notify) { + socket.on('clear_alarm', function(notify) { console.info('got clear_alarm', notify); if (alarmInProgress) { console.log('clearing alarm'); @@ -1054,7 +1050,7 @@ client.load = function load(serverSettings, callback) { window.speechSynthesis.speak(msg); } - d3.selectAll('.audio.alarms audio').each(function () { + d3.selectAll('.audio.alarms audio').each(function() { var audio = this; playAlarm(audio); setTimeout(function() { @@ -1079,30 +1075,30 @@ client.load = function load(serverSettings, callback) { $('.cobcontrol').toggle(client.settings.enable.indexOf('cob') > -1); container.toggleClass('has-minor-pills', client.plugins.hasShownType('pill-minor', client.settings)); - function prepareEntries ( ) { + function prepareEntries () { // Post processing after data is in - var temp1 = [ ]; + var temp1 = []; var sbx = client.sbx.withExtendedSettings(client.rawbg); if (client.ddata.cal && client.rawbg.isEnabled(sbx)) { - temp1 = client.ddata.sgvs.map(function (entry) { + temp1 = client.ddata.sgvs.map(function(entry) { var rawbgValue = client.rawbg.showRawBGs(entry.mgdl, entry.noise, client.ddata.cal, sbx) ? client.rawbg.calc(entry, client.ddata.cal, sbx) : 0; if (rawbgValue > 0) { return { mills: entry.mills - 2000, mgdl: rawbgValue, color: 'white', type: 'rawbg' }; } else { return null; } - }).filter(function (entry) { + }).filter(function(entry) { return entry !== null; }); } - var temp2 = client.ddata.sgvs.map(function (obj) { - return { mills: obj.mills, mgdl: obj.mgdl, direction: obj.direction, color: sgvToColor(obj.mgdl), type: 'sgv', noise: obj.noise, filtered: obj.filtered, unfiltered: obj.unfiltered}; + var temp2 = client.ddata.sgvs.map(function(obj) { + return { mills: obj.mills, mgdl: obj.mgdl, direction: obj.direction, color: sgvToColor(obj.mgdl), type: 'sgv', noise: obj.noise, filtered: obj.filtered, unfiltered: obj.unfiltered }; }); client.entries = []; client.entries = client.entries.concat(temp1, temp2); - client.entries = client.entries.concat(client.ddata.mbgs.map(function (obj) { + client.entries = client.entries.concat(client.ddata.mbgs.map(function(obj) { return { mills: obj.mills, mgdl: obj.mgdl, color: 'red', type: 'mbg', device: obj.device }; })); @@ -1111,7 +1107,7 @@ client.load = function load(serverSettings, callback) { return entry.mills > tooOld; }); - client.entries.forEach(function (point) { + client.entries.forEach(function(point) { if (point.mgdl < 39) { point.color = 'transparent'; } @@ -1131,10 +1127,9 @@ client.load = function load(serverSettings, callback) { } if (client.ddata.sgvs) { - // change the next line so that it uses the prediction if the signal gets lost (max 1/2 hr) + // TODO change the next line so that it uses the prediction if the signal gets lost (max 1/2 hr) client.ctx.data.lastUpdated = lastUpdated; client.latestSGV = client.ddata.sgvs[client.ddata.sgvs.length - 1]; - prevSGV = client.ddata.sgvs[client.ddata.sgvs.length - 2]; } client.ddata.inRetroMode = false; diff --git a/lib/client/receiveddata.js b/lib/client/receiveddata.js index be622a77..e0adf13f 100644 --- a/lib/client/receiveddata.js +++ b/lib/client/receiveddata.js @@ -4,22 +4,22 @@ var _ = require('lodash'); var TWO_DAYS = 172800000; -function mergeDataUpdate(isDelta, cachedDataArray, receivedDataArray, maxAge) { +function mergeDataUpdate (isDelta, cachedDataArray, receivedDataArray, maxAge) { - function nsArrayDiff(oldArray, newArray) { - var seen = {}; + function nsArrayDiff (oldArray, newArray) { + var seen = []; var l = oldArray.length; - + for (var i = 0; i < l; i++) { - if (oldArray[i] !== null) { - seen[oldArray[i].mills] = true; + if (oldArray[i] !== null) { + seen.push(oldArray[i].mills); } } - + var result = []; l = newArray.length; for (var j = 0; j < l; j++) { - if (!seen.hasOwnProperty(newArray[j].mills)) { + if (!seen.includes(newArray[j].mills)) { result.push(newArray[j]); //console.log('delta data found'); } } @@ -39,11 +39,11 @@ function mergeDataUpdate(isDelta, cachedDataArray, receivedDataArray, maxAge) { // purge old data from cache before updating var mAge = (isNaN(maxAge) || maxAge == null) ? TWO_DAYS : maxAge; var twoDaysAgo = new Date().getTime() - mAge; - + for (var i = 0; i < cachedDataArray.length; i++) { var element = cachedDataArray[i]; - if (element !== null && element !== undefined && element.mills <= twoDaysAgo) { - cachedDataArray.splice(i,0); + if (element !== null && element !== undefined && element.mills <= twoDaysAgo) { + cachedDataArray.splice(i, 0); } } @@ -54,7 +54,7 @@ function mergeDataUpdate(isDelta, cachedDataArray, receivedDataArray, maxAge) { }); } -function mergeTreatmentUpdate(isDelta, cachedDataArray, receivedDataArray) { +function mergeTreatmentUpdate (isDelta, cachedDataArray, receivedDataArray) { // If there was no delta data, just return the original data if (!receivedDataArray) { @@ -78,12 +78,12 @@ function mergeTreatmentUpdate(isDelta, cachedDataArray, receivedDataArray) { for (var j = 0; j < m; j++) { if (no._id === cachedDataArray[j]._id) { if (no.action === 'remove') { - cachedDataArray.splice(j,1); + cachedDataArray.splice(j, 1); break; } if (no.action === 'update') { delete no.action; - cachedDataArray.splice(j,1,no); + cachedDataArray.splice(j, 1, no); break; } } diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 463595b1..5b1c36ad 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -8,21 +8,21 @@ var DEFAULT_FOCUS = times.hours(3).msecs , WIDTH_BIG_DOTS = 800 , TOOLTIP_TRANS_MS = 100 // milliseconds , TOOLTIP_WIDTH = 150 //min-width + padding - ; +; function init (client, d3) { - var renderer = { }; + var renderer = {}; var utils = client.utils; var translate = client.translate; //chart isn't created till the client gets data, so can grab the var at init - function chart() { + function chart () { return client.chart; } - function focusRangeAdjustment ( ) { + function focusRangeAdjustment () { return client.focusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.focusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); } @@ -39,20 +39,20 @@ function init (client, d3) { return radius / focusRangeAdjustment(); }; - function tooltipLeft ( ) { + function tooltipLeft () { var windowWidth = $(client.tooltip).parent().parent().width(); var left = d3.event.pageX + TOOLTIP_WIDTH < windowWidth ? d3.event.pageX : windowWidth - TOOLTIP_WIDTH - 10; return left + 'px'; } - function hideTooltip ( ) { + function hideTooltip () { client.tooltip.transition() .duration(TOOLTIP_TRANS_MS) .style('opacity', 0); } // get the desired opacity for context chart based on the brush extent - renderer.highlightBrushPoints = function highlightBrushPoints(data) { + renderer.highlightBrushPoints = function highlightBrushPoints (data) { if (data.mills >= chart().brush.extent()[0].getTime() && data.mills <= chart().brush.extent()[1].getTime()) { return chart().futureOpacity(data.mills - client.latestSGV.mills); } else { @@ -60,20 +60,20 @@ function init (client, d3) { } }; - renderer.bubbleScale = function bubbleScale ( ) { + renderer.bubbleScale = function bubbleScale () { // a higher bubbleScale will produce smaller bubbles (it's not a radius like focusDotRadius) return (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 4 : (chart().prevChartWidth < WIDTH_BIG_DOTS ? 3 : 2)) * focusRangeAdjustment(); }; - renderer.addFocusCircles = function addFocusCircles ( ) { + renderer.addFocusCircles = function addFocusCircles () { // get slice of data so that concatenation of predictions do not interfere with subsequent updates var focusData = client.entries.slice(); if (client.sbx.pluginBase.forecastPoints) { - var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown(point) { + var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown (point) { return client.settings.showForecast.indexOf(point.info.type) > -1; }); - var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); + var maxForecastMills = _.max(_.map(shownForecastPoints, function(point) { return point.mills })); // limit lookahead to the same as lookback var focusHoursAheadMills = chart().brush.extent()[1].getTime() + client.focusRangeMS; maxForecastMills = Math.min(focusHoursAheadMills, maxForecastMills); @@ -85,20 +85,20 @@ function init (client, d3) { // selects all our data into data and uses date function to get current max date var focusCircles = chart().focus.selectAll('circle').data(focusData, client.entryToDate); - function prepareFocusCircles(sel) { + function prepareFocusCircles (sel) { var badData = []; - sel.attr('cx', function (d) { - if (!d) { - console.error('Bad data', d); - return chart().xScale(new Date(0)); - } else if (!d.mills) { - console.error('Bad data, no mills', d); - return chart().xScale(new Date(0)); - } else { - return chart().xScale(new Date(d.mills)); - } - }) - .attr('cy', function (d) { + sel.attr('cx', function(d) { + if (!d) { + console.error('Bad data', d); + return chart().xScale(new Date(0)); + } else if (!d.mills) { + console.error('Bad data, no mills', d); + return chart().xScale(new Date(0)); + } else { + return chart().xScale(new Date(d.mills)); + } + }) + .attr('cy', function(d) { var scaled = client.sbx.scaleEntry(d); if (isNaN(scaled)) { badData.push(d); @@ -107,19 +107,19 @@ function init (client, d3) { return chart().yScale(scaled); } }) - .attr('fill', function (d) { + .attr('fill', function(d) { return d.type === 'forecast' ? 'none' : d.color; }) - .attr('opacity', function (d) { + .attr('opacity', function(d) { return d.noFade ? 100 : chart().futureOpacity(d.mills - client.latestSGV.mills); }) - .attr('stroke-width', function (d) { + .attr('stroke-width', function(d) { return d.type === 'mbg' ? 2 : d.type === 'forecast' ? 2 : 0; }) - .attr('stroke', function (d) { + .attr('stroke', function(d) { return (d.type === 'mbg' ? 'white' : d.color); }) - .attr('r', function (d) { + .attr('r', function(d) { return dotRadius(d.type); }); @@ -135,8 +135,8 @@ function init (client, d3) { return; } - function getRawbgInfo ( ) { - var info = { }; + function getRawbgInfo () { + var info = {}; var sbx = client.sbx.withExtendedSettings(client.rawbg); if (d.type === 'sgv') { info.noise = client.rawbg.noiseCodeToDisplay(d.mgdl, d.noise); @@ -150,12 +150,12 @@ function init (client, d3) { var rawbgInfo = getRawbgInfo(); client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html('' + translate('BG')+ ': ' + client.sbx.scaleEntry( d ) + - (d.type === 'mbg' ? '
' + translate('Device') + ': ' + d.device : '') + - (d.type === 'forecast' && d.forecastType ? '
' + translate('Forecast Type') + ': ' + d.forecastType : '') + - (rawbgInfo.value ? '
' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + - (rawbgInfo.noise ? '
' + translate('Noise') + ': ' + rawbgInfo.noise : '') + - '
' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) + client.tooltip.html('' + translate('BG') + ': ' + client.sbx.scaleEntry(d) + + (d.type === 'mbg' ? '
' + translate('Device') + ': ' + d.device : '') + + (d.type === 'forecast' && d.forecastType ? '
' + translate('Forecast Type') + ': ' + d.forecastType : '') + + (rawbgInfo.value ? '
' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + + (rawbgInfo.noise ? '
' + translate('Noise') + ': ' + rawbgInfo.noise : '') + + '
' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) .style('left', tooltipLeft()) .style('top', (d3.event.pageY + 15) + 'px'); } @@ -171,24 +171,24 @@ function init (client, d3) { focusCircles.exit().remove(); }; - renderer.addTreatmentCircles = function addTreatmentCircles ( ) { + renderer.addTreatmentCircles = function addTreatmentCircles () { function treatmentTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
' : '') + - (d.reason ? ''+translate('Reason')+': ' + translate(d.reason) + '
' : '') + - (d.glucose ? ''+translate('BG')+': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')': '') + '
' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
' : '') + - (d.targetTop ? ''+translate('Target Top')+': ' + d.targetTop + '
' : '') + - (d.targetBottom ? ''+translate('Target Bottom')+': ' + d.targetBottom + '
' : '') + - (d.duration ? ''+translate('Duration')+': ' + Math.round(d.duration) + ' min
' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); + return '' + translate('Time') + ': ' + client.formatTime(new Date(d.mills)) + '
' + + (d.eventType ? '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
' : '') + + (d.reason ? '' + translate('Reason') + ': ' + translate(d.reason) + '
' : '') + + (d.glucose ? '' + translate('BG') + ': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')' : '') + '
' : '') + + (d.enteredBy ? '' + translate('Entered By') + ': ' + d.enteredBy + '
' : '') + + (d.targetTop ? '' + translate('Target Top') + ': ' + d.targetTop + '
' : '') + + (d.targetBottom ? '' + translate('Target Bottom') + ': ' + d.targetBottom + '
' : '') + + (d.duration ? '' + translate('Duration') + ': ' + Math.round(d.duration) + ' min
' : '') + + (d.notes ? '' + translate('Notes') + ': ' + d.notes : ''); } function announcementTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
' + - (d.eventType ? ''+translate('Announcement')+'
' : '') + - (d.notes && d.notes.length > 1 ? ''+translate('Message')+': ' + d.notes + '
' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
' : ''); + return '' + translate('Time') + ': ' + client.formatTime(new Date(d.mills)) + '
' + + (d.eventType ? '' + translate('Announcement') + '
' : '') + + (d.notes && d.notes.length > 1 ? '' + translate('Message') + ': ' + d.notes + '
' : '') + + (d.enteredBy ? '' + translate('Entered By') + ': ' + d.enteredBy + '
' : ''); } //TODO: filter in oref0 instead of here and after most people upgrade take this out @@ -199,7 +199,7 @@ function init (client, d3) { var treatCircles = chart().focus.selectAll('treatment-dot').data(client.ddata.treatments.filter(function(treatment) { var notCarbsOrInsulin = !treatment.carbs && !treatment.insulin; - var notTempOrProfile = ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + var notTempOrProfile = !_.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); var notes = treatment.notes || ''; var enteredBy = treatment.enteredBy || ''; @@ -211,8 +211,8 @@ function init (client, d3) { return notCarbsOrInsulin && !treatment.duration && notTempOrProfile && notOpenAPSSpam; })); - function prepareTreatCircles(sel) { - function strokeColor(d) { + function prepareTreatCircles (sel) { + function strokeColor (d) { var color = 'white'; if (d.isAnnouncement) { color = 'orange'; @@ -222,7 +222,7 @@ function init (client, d3) { return color; } - function fillColor(d) { + function fillColor (d) { var color = 'grey'; if (d.isAnnouncement) { color = 'orange'; @@ -232,13 +232,13 @@ function init (client, d3) { return color; } - sel.attr('cx', function (d) { - return chart().xScale(new Date(d.mills)); - }) - .attr('cy', function (d) { + sel.attr('cx', function(d) { + return chart().xScale(new Date(d.mills)); + }) + .attr('cy', function(d) { return chart().yScale(client.sbx.scaleEntry(d)); }) - .attr('r', function () { + .attr('r', function() { return dotRadius('mbg'); }) .attr('stroke-width', 2) @@ -253,7 +253,7 @@ function init (client, d3) { // if new circle then just display prepareTreatCircles(treatCircles.enter().append('circle')) - .on('mouseover', function (d) { + .on('mouseover', function(d) { client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) .style('left', tooltipLeft()) @@ -263,7 +263,7 @@ function init (client, d3) { var durationTreatments = client.ddata.treatments.filter(function(treatment) { return !treatment.carbs && !treatment.insulin && treatment.duration && - ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + !_.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); }); //use the processed temp target so there are no overlaps @@ -272,7 +272,7 @@ function init (client, d3) { // treatments with duration var treatRects = chart().focus.selectAll('.g-duration').data(durationTreatments); - function fillColor(d) { + function fillColor (d) { // this is going to be updated by Event Type var color = 'grey'; if (d.eventType === 'Exercise') { @@ -305,20 +305,20 @@ function init (client, d3) { .attr('transform', rectTranslate); chart().focus.selectAll('.g-duration-rect').transition() - .attr('width', function (d) { + .attr('width', function(d) { return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); }); chart().focus.selectAll('.g-duration-text').transition() - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + .attr('transform', function(d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills))) / 2 + ',' + 10 + ')'; }); // if new rect then just display var gs = treatRects.enter().append('g') - .attr('class','g-duration') + .attr('class', 'g-duration') .attr('transform', rectTranslate) - .on('mouseover', function (d) { + .on('mouseover', function(d) { client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) .style('left', tooltipLeft()) @@ -328,7 +328,7 @@ function init (client, d3) { gs.append('rect') .attr('class', 'g-duration-rect') - .attr('width', function (d) { + .attr('width', function(d) { return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); }) .attr('height', rectHeight) @@ -343,10 +343,10 @@ function init (client, d3) { .attr('fill', 'white') .attr('text-anchor', 'middle') .attr('dy', '.35em') - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + .attr('transform', function(d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills))) / 2 + ',' + 10 + ')'; }) - .text(function (d) { + .text(function(d) { if (d.eventType === 'Temporary Target') { return ''; } @@ -354,14 +354,14 @@ function init (client, d3) { }); }; - renderer.addContextCircles = function addContextCircles ( ) { + renderer.addContextCircles = function addContextCircles () { // bind up the context chart data to an array of circles var contextCircles = chart().context.selectAll('circle').data(client.entries); - function prepareContextCircles(sel) { + function prepareContextCircles (sel) { var badData = []; - sel.attr('cx', function (d) { return chart().xScale2(new Date(d.mills)); }) - .attr('cy', function (d) { + sel.attr('cx', function(d) { return chart().xScale2(new Date(d.mills)); }) + .attr('cy', function(d) { var scaled = client.sbx.scaleEntry(d); if (isNaN(scaled)) { badData.push(d); @@ -370,11 +370,11 @@ function init (client, d3) { return chart().yScale2(scaled); } }) - .attr('fill', function (d) { return d.color; }) - .style('opacity', function (d) { return renderer.highlightBrushPoints(d) }) - .attr('stroke-width', function (d) { return d.type === 'mbg' ? 2 : 0; }) - .attr('stroke', function ( ) { return 'white'; }) - .attr('r', function (d) { return d.type === 'mbg' ? 4 : 2; }); + .attr('fill', function(d) { return d.color; }) + .style('opacity', function(d) { return renderer.highlightBrushPoints(d) }) + .attr('stroke-width', function(d) { return d.type === 'mbg' ? 2 : 0; }) + .attr('stroke', function() { return 'white'; }) + .attr('r', function(d) { return d.type === 'mbg' ? 4 : 2; }); if (badData.length > 0) { console.warn('Bad Data: isNaN(sgv)', badData); @@ -392,13 +392,13 @@ function init (client, d3) { contextCircles.exit().remove(); }; - function calcTreatmentRadius(treatment, opts, carbratio) { + function calcTreatmentRadius (treatment, opts, carbratio) { var CR = treatment.CR || carbratio || 20; var carbsOrInsulin = CR; - if ( treatment.carbs ) { - carbsOrInsulin = treatment.carbs; - } else if ( treatment.insulin ) { - carbsOrInsulin = treatment.insulin * CR; + if (treatment.carbs) { + carbsOrInsulin = treatment.carbs; + } else if (treatment.insulin) { + carbsOrInsulin = treatment.insulin * CR; } // R1 determines the size of the treatment dot @@ -406,8 +406,7 @@ function init (client, d3) { , R2 = R1 // R3/R4 determine how far from the treatment dot the labels are placed , R3 = R1 + 8 / opts.scale - , R4 = R1 + 25 / opts.scale - ; + , R4 = R1 + 25 / opts.scale; return { R1: R1 @@ -418,17 +417,17 @@ function init (client, d3) { }; } - function prepareArc(treatment, radius) { + function prepareArc (treatment, radius) { var arc_data = [ // white carb half-circle on top - { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, - { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, + { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 } + , { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, // blue insulin half-circle on bottom { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, // these form a very short transparent arc along the bottom of an insulin treatment to position the label // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 }, - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } + { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 } + , { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } ]; arc_data[0].outlineOnly = !treatment.carbs; @@ -450,16 +449,16 @@ function init (client, d3) { arc_data[1].element = arc_data[1].element + " " + treatment.foodType; } - if ( treatment.insulin > 0) { - var dosage_units = '' + Math.round(treatment.insulin * 100)/100; - + if (treatment.insulin > 0) { + var dosage_units = '' + Math.round(treatment.insulin * 100) / 100; + var unit_of_measurement = ' U'; // One international unit of insulin (1 IU) is shown as '1 U' var enteredBy = '' + treatment.enteredBy; - - if ( treatment.insulin < 1 && !treatment.carbs && enteredBy.indexOf('openaps') > -1) { // don't show the unit of measurement for insulin boluses < 1 without carbs (e.g. oref0 SMB's). Otherwise lot's of small insulin only dosages are often unreadable - unit_of_measurement = ''; - // remove leading zeros to avoid overlap with adjacent boluses - dosage_units = (dosage_units+"").replace(/^0/,""); + + if (treatment.insulin < 1 && !treatment.carbs && enteredBy.indexOf('openaps') > -1) { // don't show the unit of measurement for insulin boluses < 1 without carbs (e.g. oref0 SMB's). Otherwise lot's of small insulin only dosages are often unreadable + unit_of_measurement = ''; + // remove leading zeros to avoid overlap with adjacent boluses + dosage_units = (dosage_units + "").replace(/^0/, ""); } arc_data[3].element = dosage_units + unit_of_measurement; @@ -470,16 +469,16 @@ function init (client, d3) { } var arc = d3.svg.arc() - .innerRadius(function (d) { + .innerRadius(function(d) { return 5 * d.inner; }) - .outerRadius(function (d) { + .outerRadius(function(d) { return 5 * d.outer; }) - .endAngle(function (d) { + .endAngle(function(d) { return d.start; }) - .startAngle(function (d) { + .startAngle(function(d) { return d.end; }); @@ -489,27 +488,27 @@ function init (client, d3) { }; } - function isInRect(x,y,rect) { + function isInRect (x, y, rect) { return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); } - function appendTreatments(treatment, arc) { + function appendTreatments (treatment, arc) { function boluscalcTooltip (treatment) { if (!treatment.boluscalc) { return ''; } var html = '
'; - html += (treatment.boluscalc.othercorrection ? ''+translate('Other correction')+': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
' : ''); - html += (treatment.boluscalc.profile ? ''+translate('Profile used')+': ' + treatment.boluscalc.profile + '
' : ''); + html += (treatment.boluscalc.othercorrection ? '' + translate('Other correction') + ': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
' : ''); + html += (treatment.boluscalc.profile ? '' + translate('Profile used') + ': ' + treatment.boluscalc.profile + '
' : ''); if (treatment.boluscalc.foods && treatment.boluscalc.foods.length) { html += ''; - for (var fi=0; fi'; - html += ''; - html += ''; + html += ''; + html += ''; + html += ''; html += ''; } html += '
' + translate('Food') + '
'+ (f.portion*f.portions).toFixed(1) + ' ' + f.unit + '('+ (f.carbs*f.portions).toFixed(1) + ' g)' + f.name + '' + (f.portion * f.portions).toFixed(1) + ' ' + f.unit + '(' + (f.carbs * f.portions).toFixed(1) + ' g)
'; @@ -517,22 +516,22 @@ function init (client, d3) { return html; } - function treatmentTooltip() { + function treatmentTooltip () { client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); client.tooltip.html('' + translate('Time') + ': ' + client.formatTime(new Date(treatment.mills)) + '
' + '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(treatment.eventType)) + '
' + - (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
' : '') + - (treatment.protein ? '' + translate('Protein') + ': ' + treatment.protein + '
' : '') + - (treatment.fat ? '' + translate('Fat') + ': ' + treatment.fat + '
' : '') + - (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round( treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
' : '') + - (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
' : '') + - (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
' : '') + - (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
' : '') + - (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
' : '') + - (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + - boluscalcTooltip(treatment) - ) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); + (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
' : '') + + (treatment.protein ? '' + translate('Protein') + ': ' + treatment.protein + '
' : '') + + (treatment.fat ? '' + translate('Fat') + ': ' + treatment.fat + '
' : '') + + (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round(treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
' : '') + + (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
' : '') + + (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
' : '') + + (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
' : '') + + (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
' : '') + + (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + + boluscalcTooltip(treatment) + ) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); } var newTime; @@ -547,104 +546,104 @@ function init (client, d3) { var left = d3.event.x + TOOLTIP_WIDTH < windowWidth ? d3.event.x : windowWidth - TOOLTIP_WIDTH - 10; client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9) .style('left', left + 'px') - .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); + .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); deleteRect = { - x: 0, - y: 0, - width: 50, - height: chart().yScale(chart().yScale.domain()[0]) + x: 0 + , y: 0 + , width: 50 + , height: chart().yScale(chart().yScale.domain()[0]) }; chart().drag.append('rect') .attr({ - class:'drag-droparea', - x: deleteRect.x, - y: deleteRect.y, - width: deleteRect.width, - height: deleteRect.height, - fill: 'red', - opacity: 0.4, - rx: 10, - ry: 10 + class: 'drag-droparea' + , x: deleteRect.x + , y: deleteRect.y + , width: deleteRect.width + , height: deleteRect.height + , fill: 'red' + , opacity: 0.4 + , rx: 10 + , ry: 10 }); chart().drag.append('text') .attr({ - class:'drag-droparea', - x: deleteRect.x + deleteRect.width / 2, - y: deleteRect.y + deleteRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'red', - 'text-anchor': 'middle', - dy: '.35em', - transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' + class: 'drag-droparea' + , x: deleteRect.x + deleteRect.width / 2 + , y: deleteRect.y + deleteRect.height / 2 + , 'font-size': 15 + , 'font-weight': 'bold' + , fill: 'red' + , 'text-anchor': 'middle' + , dy: '.35em' + , transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' }) .text(translate('Remove')); if (treatment.insulin && treatment.carbs) { carbsRect = { - x: 0, - y: 0, - width: chart().charts.attr('width'), - height: 50 + x: 0 + , y: 0 + , width: chart().charts.attr('width') + , height: 50 }; insulinRect = { - x: 0, - y: chart().yScale(chart().yScale.domain()[0]) - 50, - width: chart().charts.attr('width'), - height: 50 + x: 0 + , y: chart().yScale(chart().yScale.domain()[0]) - 50 + , width: chart().charts.attr('width') + , height: 50 }; chart().drag.append('rect') .attr({ - class:'drag-droparea', - x: carbsRect.x, - y: carbsRect.y, - width: carbsRect.width, - height: carbsRect.height, - fill: 'white', - opacity: 0.4, - rx: 10, - ry: 10 + class: 'drag-droparea' + , x: carbsRect.x + , y: carbsRect.y + , width: carbsRect.width + , height: carbsRect.height + , fill: 'white' + , opacity: 0.4 + , rx: 10 + , ry: 10 }); chart().drag.append('text') .attr({ - class:'drag-droparea', - x: carbsRect.x + carbsRect.width / 2, - y: carbsRect.y + carbsRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'white', - 'text-anchor': 'middle', - dy: '.35em' + class: 'drag-droparea' + , x: carbsRect.x + carbsRect.width / 2 + , y: carbsRect.y + carbsRect.height / 2 + , 'font-size': 15 + , 'font-weight': 'bold' + , fill: 'white' + , 'text-anchor': 'middle' + , dy: '.35em' }) .text(translate('Move carbs')); chart().drag.append('rect') .attr({ - class:'drag-droparea', - x: insulinRect.x, - y: insulinRect.y, - width: insulinRect.width, - height: insulinRect.height, - fill: '#0099ff', - opacity: 0.4, - rx: 10, - ry: 10 + class: 'drag-droparea' + , x: insulinRect.x + , y: insulinRect.y + , width: insulinRect.width + , height: insulinRect.height + , fill: '#0099ff' + , opacity: 0.4 + , rx: 10 + , ry: 10 }); chart().drag.append('text') .attr({ - class:'drag-droparea', - x: insulinRect.x + insulinRect.width / 2, - y: insulinRect.y + insulinRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: '#0099ff', - 'text-anchor': 'middle', - dy: '.35em' + class: 'drag-droparea' + , x: insulinRect.x + insulinRect.width / 2 + , y: insulinRect.y + insulinRect.height / 2 + , 'font-size': 15 + , 'font-weight': 'bold' + , fill: '#0099ff' + , 'text-anchor': 'middle' + , dy: '.35em' }) .text(translate('Move insulin')); } - chart().basals.attr('display','none'); + chart().basals.attr('display', 'none'); operation = 'Move'; }) @@ -670,22 +669,22 @@ function init (client, d3) { newTime = new Date(chart().xScale.invert(x)); var minDiff = times.msecs(newTime.getTime() - treatment.mills).mins.toFixed(0); client.tooltip.html( - '' + translate('Operation') + ': ' + translate(operation) + '
' - + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
' - + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') - ); + '' + translate('Operation') + ': ' + translate(operation) + '
' + + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
' + + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') + ); chart().drag.selectAll('.arrow').remove(); chart().drag.append('line') .attr({ - 'class':'arrow', - 'marker-end':'url(#arrow)', - 'x1': chart().xScale(new Date(treatment.mills)), - 'y1': chart().yScale(client.sbx.scaleEntry(treatment)), - 'x2': x, - 'y2': y, - 'stroke-width': 2, - 'stroke': 'white' + 'class': 'arrow' + , 'marker-end': 'url(#arrow)' + , 'x1': chart().xScale(new Date(treatment.mills)) + , 'y1': chart().yScale(client.sbx.scaleEntry(treatment)) + , 'x2': x + , 'y2': y + , 'stroke-width': 2 + , 'stroke': 'white' }); }) @@ -695,15 +694,14 @@ function init (client, d3) { hideTooltip(); switch (operation) { case 'Move': - if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] }))) { client.socket.emit( - 'dbUpdate', - { - collection: 'treatments', - _id: treatment._id, - data: { created_at: newTime.toISOString() } - }, - function callback(result) { + 'dbUpdate', { + collection: 'treatments' + , _id: treatment._id + , data: { created_at: newTime.toISOString() } + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -715,13 +713,12 @@ function init (client, d3) { case 'Remove insulin': if (window.confirm(translate('Remove insulin from treatment ?'))) { client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } - }, - function callback(result) { + 'dbUpdateUnset', { + collection: 'treatments' + , _id: treatment._id + , data: { insulin: 1 } + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -733,13 +730,12 @@ function init (client, d3) { case 'Remove carbs': if (window.confirm(translate('Remove carbs from treatment ?'))) { client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } - }, - function callback(result) { + 'dbUpdateUnset', { + collection: 'treatments' + , _id: treatment._id + , data: { carbs: 1 } + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -751,12 +747,11 @@ function init (client, d3) { case 'Remove': if (window.confirm(translate('Remove treatment ?'))) { client.socket.emit( - 'dbRemove', - { - collection: 'treatments', - _id: treatment._id - }, - function callback(result) { + 'dbRemove', { + collection: 'treatments' + , _id: treatment._id + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -766,13 +761,12 @@ function init (client, d3) { } break; case 'Move insulin': - if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] }))) { client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } + 'dbUpdateUnset', { + collection: 'treatments' + , _id: treatment._id + , data: { insulin: 1 } } ); newTreatment = _.cloneDeep(treatment); @@ -781,12 +775,11 @@ function init (client, d3) { delete newTreatment.carbs; newTreatment.created_at = newTime.toISOString(); client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { + 'dbAdd', { + collection: 'treatments' + , data: newTreatment + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -796,13 +789,12 @@ function init (client, d3) { } break; case 'Move carbs': - if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] }))) { client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } + 'dbUpdateUnset', { + collection: 'treatments' + , _id: treatment._id + , data: { carbs: 1 } } ); newTreatment = _.cloneDeep(treatment); @@ -811,12 +803,11 @@ function init (client, d3) { delete newTreatment.insulin; newTreatment.created_at = newTime.toISOString(); client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { + 'dbAdd', { + collection: 'treatments' + , data: newTreatment + } + , function callback (result) { console.log(result); chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } @@ -826,7 +817,7 @@ function init (client, d3) { } break; } - chart().basals.attr('display',''); + chart().basals.attr('display', ''); }); var treatmentDots = chart().focus.selectAll('treatment-insulincarbs') @@ -845,16 +836,16 @@ function init (client, d3) { treatmentDots.append('path') .attr('class', 'path') - .attr('fill', function (d) { + .attr('fill', function(d) { return d.outlineOnly ? 'transparent' : d.color; }) - .attr('stroke-width', function (d) { + .attr('stroke-width', function(d) { return d.outlineOnly ? 1 : 0; }) - .attr('stroke', function (d) { + .attr('stroke', function(d) { return d.color; }) - .attr('id', function (d, i) { + .attr('id', function(d, i) { return 's' + i; }) .attr('d', arc.svg); @@ -862,42 +853,42 @@ function init (client, d3) { return treatmentDots; } - function appendLabels(treatmentDots, arc, opts) { + function appendLabels (treatmentDots, arc, opts) { // labels for carbs and insulin if (opts.showLabels) { var label = treatmentDots.append('g') .attr('class', 'path') .attr('id', 'label') .style('fill', 'white'); - + // reduce the treatment label font size to make it readable with SMB - var fontBaseSize = (opts.treatments >= 30) ? 40 : 50 - Math.floor((25-opts.treatments)/30 * 10); + var fontBaseSize = (opts.treatments >= 30) ? 40 : 50 - Math.floor((25 - opts.treatments) / 30 * 10); label.append('text') .style('font-size', fontBaseSize / opts.scale) .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') .attr('text-anchor', 'middle') .attr('dy', '.35em') - .attr('transform', function (d) { + .attr('transform', function(d) { d.outerRadius = d.outerRadius * 2.1; d.innerRadius = d.outerRadius * 2.1; return 'translate(' + arc.svg.centroid(d) + ')'; }) - .text(function (d) { + .text(function(d) { return d.element; }); } } - renderer.drawTreatments = function drawTreatments(client) { - + renderer.drawTreatments = function drawTreatments (client) { + var treatmentCount = 0; chart().focus.selectAll('.draggable-treatment').remove(); - + _.forEach(client.ddata.treatments, function eachTreatment (d) { - if (Number(d.insulin) > 0 || Number(d.carbs) > 0) { treatmentCount += 1; }; + if (Number(d.insulin) > 0 || Number(d.carbs) > 0) { treatmentCount += 1; } }); - + // add treatment bubbles _.forEach(client.ddata.treatments, function eachTreatment (d) { renderer.drawTreatment(d, { @@ -906,9 +897,9 @@ function init (client, d3) { , treatments: treatmentCount }, client.sbx.data.profile.getCarbRatio(new Date())); }); - }; + } - renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { + renderer.drawTreatment = function drawTreatment (treatment, opts, carbratio) { if (!treatment.carbs && !treatment.insulin) { return; } @@ -929,7 +920,7 @@ function init (client, d3) { var arc = prepareArc(treatment, radius); var treatmentDots = appendTreatments(treatment, arc); appendLabels(treatmentDots, arc, opts); - }; + } renderer.addBasals = function addBasals (client) { @@ -959,20 +950,20 @@ function init (client, d3) { while (date <= to) { var basalvalue = profile.getTempBasal(date); if (!_.isEqual(lastbasal, basalvalue)) { - linedata.push( { d: date, b: basalvalue.totalbasal } ); - notemplinedata.push( { d: date, b: basalvalue.basal } ); + linedata.push({ d: date, b: basalvalue.totalbasal }); + notemplinedata.push({ d: date, b: basalvalue.basal }); if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { - tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: basalvalue.totalbasal } ); + tempbasalareadata.push({ d: date, b: basalvalue.tempbasal }); + basalareadata.push({ d: date, b: 0 }); + comboareadata.push({ d: date, b: basalvalue.totalbasal }); } else if (basalvalue.treatment) { - tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: 0 } ); + tempbasalareadata.push({ d: date, b: basalvalue.totalbasal }); + basalareadata.push({ d: date, b: 0 }); + comboareadata.push({ d: date, b: 0 }); } else { - tempbasalareadata.push( { d: date, b: 0 } ); - basalareadata.push( { d: date, b: basalvalue.totalbasal } ); - comboareadata.push( { d: date, b: 0 } ); + tempbasalareadata.push({ d: date, b: 0 }); + basalareadata.push({ d: date, b: basalvalue.totalbasal }); + comboareadata.push({ d: date, b: 0 }); } } lastbasal = basalvalue; @@ -981,15 +972,15 @@ function init (client, d3) { var toTempBasal = profile.getTempBasal(to); - linedata.push( { d: to, b: toTempBasal.totalbasal } ); - notemplinedata.push( { d: to, b: toTempBasal.basal } ); - basalareadata.push( { d: to, b: toTempBasal.basal } ); - tempbasalareadata.push( { d: to, b: toTempBasal.totalbasal } ); - comboareadata.push( { d: to, b: toTempBasal.totalbasal } ); + linedata.push({ d: to, b: toTempBasal.totalbasal }); + notemplinedata.push({ d: to, b: toTempBasal.basal }); + basalareadata.push({ d: to, b: toTempBasal.basal }); + tempbasalareadata.push({ d: to, b: toTempBasal.totalbasal }); + comboareadata.push({ d: to, b: toTempBasal.totalbasal }); - var max_linedata = d3.max(linedata, function (d) { return d.b; }); - var max_notemplinedata = d3.max(notemplinedata, function (d) { return d.b; }); - var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1 ); + var max_linedata = d3.max(linedata, function(d) { return d.b; }); + var max_notemplinedata = d3.max(notemplinedata, function(d) { return d.b; }); + var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1); chart().maxBasalValue = max; chart().yScaleBasals.domain('icicle' === mode ? [0, max] : [max, 0]); @@ -1061,7 +1052,7 @@ function init (client, d3) { .attr('fill', '#0099ff') .attr('text-anchor', 'middle') .attr('dy', '.35em') - .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to))/2)) + .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to)) / 2)) .attr('y', 10) .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (isNaN(t.absolute) ? '' : Number(t.absolute).toFixed(2) + 'U') + (t.relative ? 'C: +' + t.relative + 'U' : '')); // better hide if not fit @@ -1080,19 +1071,19 @@ function init (client, d3) { } function profileTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
' : '') + - (d.endprofile ? ''+translate('End of profile')+': ' + d.endprofile + '
' : '') + - (d.profile ? ''+translate('Profile')+': ' + d.profile + '
' : '') + - (d.duration ? ''+translate('Duration')+': ' + d.duration + translate('mins') + '
' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); + return '' + translate('Time') + ': ' + client.formatTime(new Date(d.mills)) + '
' + + (d.eventType ? '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
' : '') + + (d.endprofile ? '' + translate('End of profile') + ': ' + d.endprofile + '
' : '') + + (d.profile ? '' + translate('Profile') + ': ' + d.profile + '
' : '') + + (d.duration ? '' + translate('Duration') + ': ' + d.duration + translate('mins') + '
' : '') + + (d.enteredBy ? '' + translate('Entered By') + ': ' + d.enteredBy + '
' : '') + + (d.notes ? '' + translate('Notes') + ': ' + d.notes : ''); } // calculate position of profile on left side var from = chart().brush.extent()[0].getTime(); var to = chart().brush.extent()[1].getTime(); - var mult = (to-from) / times.hours(24).msecs; + var mult = (to - from) / times.hours(24).msecs; from += times.mins(20 * mult).msecs; var mode = client.settings.extendedSettings.basal.render; @@ -1106,12 +1097,12 @@ function init (client, d3) { _.forEach(client.ddata.profileTreatments, function eachTreatment (d) { if (d.duration && !d.cuttedby) { - data.push({ - cutting: d.profile - , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) - , mills: times.mins(d.duration).msecs + d.mills - , end: true - }); + data.push({ + cutting: d.profile + , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) + , mills: times.mins(d.duration).msecs + d.mills + , end: true + }); } }); @@ -1119,24 +1110,24 @@ function init (client, d3) { var topOfText = ('icicle' === mode ? chart().maxBasalValue + 0.05 : -0.05); - var generateText = function (t) { - var sign = t.first ? '▲▲▲' : '▬▬▬'; - var ret; - if (t.cutting) { - ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; - } else { - ret = sign + ' ' + t.profile + ' ' + sign; - } - return ret; + var generateText = function(t) { + var sign = t.first ? '▲▲▲' : '▬▬▬'; + var ret; + if (t.cutting) { + ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; + } else { + ret = sign + ' ' + t.profile + ' ' + sign; + } + return ret; }; treatProfiles.transition().duration(0) - .attr('transform', function (t) { + .attr('transform', function(t) { // change text of record on left side return 'rotate(-90,' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + - 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; }). - text(generateText); + text(generateText); treatProfiles.enter().append('text') .attr('class', 'g-profile') @@ -1145,12 +1136,12 @@ function init (client, d3) { .attr('fill', '#0099ff') .attr('text-anchor', 'end') .attr('dy', '.35em') - .attr('transform', function (t) { + .attr('transform', function(t) { return 'rotate(-90 ' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; }) .text(generateText) - .on('mouseover', function (d) { + .on('mouseover', function(d) { client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); client.tooltip.html(profileTooltip(d)) .style('left', (d3.event.pageX) + 'px') diff --git a/lib/data/dataloader.js b/lib/data/dataloader.js index 60a7bf36..c9c24b2d 100644 --- a/lib/data/dataloader.js +++ b/lib/data/dataloader.js @@ -11,6 +11,7 @@ var ONE_DAY = 86400000, function uniq(a) { var seen = {}; return a.filter(function(item) { + // eslint-disable-next-line no-prototype-builtins return seen.hasOwnProperty(item.mills) ? false : (seen[item.mills] = true); }); } diff --git a/lib/data/ddata.js b/lib/data/ddata.js index a055b9f3..1912ca4a 100644 --- a/lib/data/ddata.js +++ b/lib/data/ddata.js @@ -5,270 +5,269 @@ var times = require('../times'); var DEVICE_TYPE_FIELDS = ['uploader', 'pump', 'openaps', 'loop', 'xdripjs']; -function init() { +function init () { - var ddata = { - sgvs: [], - treatments: [], - mbgs: [], - cals: [], - profiles: [], - devicestatus: [], - food: [], - activity: [], - lastUpdated: 0 + var ddata = { + sgvs: [] + , treatments: [] + , mbgs: [] + , cals: [] + , profiles: [] + , devicestatus: [] + , food: [] + , activity: [] + , lastUpdated: 0 + }; + + ddata.clone = function clone () { + return _.clone(ddata, function(value) { + //special handling of mongo ObjectID's + //see https://github.com/lodash/lodash/issues/602#issuecomment-47414964 + + //instead of requiring Mongo.ObjectID here and having it get pulled into the bundle + //we'll look for the toHexString function and then assume it's an ObjectID + if (value && value.toHexString && value.toHexString.call && value.toString && value.toString.call) { + return value.toString(); + } + }); + }; + + ddata.splitRecent = function splitRecent (time, cutoff, max, treatmentsToo) { + var result = { + first: {} + , rest: {} }; - ddata.clone = function clone() { - return _.clone(ddata, function(value) { - //special handling of mongo ObjectID's - //see https://github.com/lodash/lodash/issues/602#issuecomment-47414964 + function recent (item) { + return item.mills >= time - cutoff; + } - //instead of requiring Mongo.ObjectID here and having it get pulled into the bundle - //we'll look for the toHexString function and then assume it's an ObjectID - if (value && value.toHexString && value.toHexString.call && value.toString && value.toString.call) { - return value.toString(); - } - }); - }; + function filterMax (item) { + return item.mills >= time - max; + } - ddata.splitRecent = function splitRecent(time, cutoff, max, treatmentsToo) { - var result = { - first: {}, - rest: {} - }; + function partition (field, filter) { + var data; + if (filter) { + data = ddata[field].filter(filterMax); + } else { + data = ddata[field]; + } - function recent(item) { - return item.mills >= time - cutoff; + var parts = _.partition(data, recent); + result.first[field] = parts[0]; + result.rest[field] = parts[1]; + } + + partition('treatments', treatmentsToo ? filterMax : false); + + result.first.devicestatus = ddata.recentDeviceStatus(time); + + result.first.sgvs = ddata.sgvs.filter(filterMax); + result.first.cals = ddata.cals; + + var profiles = _.cloneDeep(ddata.profiles); + if (profiles && profiles[0]) { + Object.keys(profiles[0].store).forEach(k => { + if (k.indexOf('@@@@@') > 0) { + delete profiles[0].store[k]; } + }) + } + result.first.profiles = profiles; - function filterMax(item) { - return item.mills >= time - max; + result.rest.mbgs = ddata.mbgs.filter(filterMax); + result.rest.food = ddata.food; + result.rest.activity = ddata.activity; + + console.log('results.first size', JSON.stringify(result.first).length, 'bytes'); + console.log('results.rest size', JSON.stringify(result.rest).length, 'bytes'); + + return result; + }; + + ddata.recentDeviceStatus = function recentDeviceStatus (time) { + + var deviceAndTypes = + _.chain(ddata.devicestatus) + .map(function eachStatus (status) { + return _.chain(status) + .keys() + .filter(function isExcluded (key) { + return _.includes(DEVICE_TYPE_FIELDS, key); + }) + .map(function toDeviceTypeKey (key) { + return { + device: status.device + , type: key + }; + }) + .value(); + }) + .flatten() + .uniqWith(_.isEqual) + .value(); + + //console.info('>>>deviceAndTypes', deviceAndTypes); + + var rv = _.chain(deviceAndTypes) + .map(function findMostRecent (deviceAndType) { + return _.chain(ddata.devicestatus) + .filter(function isSameDeviceType (status) { + return status.device === deviceAndType.device && _.has(status, deviceAndType.type) + }) + .filter(function notInTheFuture (status) { + return status.mills <= time; + }) + .sortBy('mills') + .takeRight(10) + .value(); + }).value(); + + var merged = [].concat.apply([], rv); + + rv = _.chain(merged) + .filter(_.isObject) + .uniq('_id') + .sortBy('mills') + .value(); + + return rv; + + }; + + ddata.processDurations = function processDurations (treatments, keepzeroduration) { + + treatments = _.uniqBy(treatments, 'mills'); + + // cut temp basals by end events + // better to do it only on data update + var endevents = treatments.filter(function filterEnd (t) { + return !t.duration; + }); + + function cutIfInInterval (base, end) { + if (base.mills < end.mills && base.mills + times.mins(base.duration).msecs > end.mills) { + base.duration = times.msecs(end.mills - base.mills).mins; + if (end.profile) { + base.cuttedby = end.profile; + end.cutting = base.profile; } + } + } - function partition(field, filter) { - var data; - if (filter) { - data = ddata[field].filter(filterMax); - } else { - data = ddata[field]; - } + // cut by end events + treatments.forEach(function allTreatments (t) { + if (t.duration) { + endevents.forEach(function allEndevents (e) { + cutIfInInterval(t, e); + }); + } + }); - var parts = _.partition(data, recent); - result.first[field] = parts[0]; - result.rest[field] = parts[1]; + // cut by overlaping events + treatments.forEach(function allTreatments (t) { + if (t.duration) { + treatments.forEach(function allEndevents (e) { + cutIfInInterval(t, e); + }); + } + }); + + if (keepzeroduration) { + return treatments; + } else { + return treatments.filter(function filterEnd (t) { + return t.duration; + }); + } + }; + + ddata.processTreatments = function processTreatments (preserveOrignalTreatments) { + + // filter & prepare 'Site Change' events + ddata.sitechangeTreatments = ddata.treatments.filter(function filterSensor (t) { + return t.eventType.indexOf('Site Change') > -1; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + + // filter & prepare 'Insulin Change' events + ddata.insulinchangeTreatments = ddata.treatments.filter(function filterInsulin (t) { + return t.eventType.indexOf('Insulin Change') > -1; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + + // filter & prepare 'Pump Battery Change' events + ddata.batteryTreatments = ddata.treatments.filter(function filterSensor (t) { + return t.eventType.indexOf('Pump Battery Change') > -1; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + + // filter & prepare 'Sensor' events + ddata.sensorTreatments = ddata.treatments.filter(function filterSensor (t) { + return t.eventType.indexOf('Sensor') > -1; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + + // filter & prepare 'Profile Switch' events + var profileTreatments = ddata.treatments.filter(function filterProfiles (t) { + return t.eventType === 'Profile Switch'; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + if (preserveOrignalTreatments) + profileTreatments = _.cloneDeep(profileTreatments); + ddata.profileTreatments = ddata.processDurations(profileTreatments, true); + + // filter & prepare 'Combo Bolus' events + ddata.combobolusTreatments = ddata.treatments.filter(function filterComboBoluses (t) { + return t.eventType === 'Combo Bolus'; + }).sort(function(a, b) { + return a.mills > b.mills; + }); + + // filter & prepare temp basals + var tempbasalTreatments = ddata.treatments.filter(function filterBasals (t) { + return t.eventType && t.eventType.indexOf('Temp Basal') > -1; + }); + if (preserveOrignalTreatments) + tempbasalTreatments = _.cloneDeep(tempbasalTreatments); + ddata.tempbasalTreatments = ddata.processDurations(tempbasalTreatments, false); + + // filter temp target + var tempTargetTreatments = ddata.treatments.filter(function filterTargets (t) { + //check for a units being sent + if (t.units) { + if (t.units == 'mmol') { + //convert to mgdl + t.targetTop = t.targetTop * 18; + t.targetBottom = t.targetBottom * 18; + t.units = 'mg/dl'; } + } + //if we have a temp target thats below 20, assume its mmol and convert to mgdl for safety. + if (t.targetTop < 20) { + t.targetTop = t.targetTop * 18; + t.units = 'mg/dl'; + } + if (t.targetBottom < 20) { + t.targetBottom = t.targetBottom * 18; + t.units = 'mg/dl'; + } + return t.eventType && t.eventType.indexOf('Temporary Target') > -1; + }); + if (preserveOrignalTreatments) + tempTargetTreatments = _.cloneDeep(tempTargetTreatments); + ddata.tempTargetTreatments = ddata.processDurations(tempTargetTreatments, false); - partition('treatments', treatmentsToo ? filterMax : false); + }; - result.first.devicestatus = ddata.recentDeviceStatus(time); - - result.first.sgvs = ddata.sgvs.filter(filterMax); - result.first.cals = ddata.cals; - - var profiles = _.cloneDeep(ddata.profiles); - if (profiles && profiles[0]) - for (var k in profiles[0].store) { - if (profiles[0].store.hasOwnProperty(k)) { - if (k.indexOf('@@@@@') > 0) { - delete profiles[0].store[k]; - } - } - } - result.first.profiles = profiles; - - result.rest.mbgs = ddata.mbgs.filter(filterMax); - result.rest.food = ddata.food; - result.rest.activity = ddata.activity; - - console.log('results.first size', JSON.stringify(result.first).length, 'bytes'); - console.log('results.rest size', JSON.stringify(result.rest).length, 'bytes'); - - return result; - }; - - ddata.recentDeviceStatus = function recentDeviceStatus(time) { - - var deviceAndTypes = - _.chain(ddata.devicestatus) - .map(function eachStatus(status) { - return _.chain(status) - .keys() - .filter(function isExcluded(key) { - return _.includes(DEVICE_TYPE_FIELDS, key); - }) - .map(function toDeviceTypeKey(key) { - return { - device: status.device, - type: key - }; - }) - .value(); - }) - .flatten() - .uniqWith(_.isEqual) - .value(); - - //console.info('>>>deviceAndTypes', deviceAndTypes); - - var rv = _.chain(deviceAndTypes) - .map(function findMostRecent(deviceAndType) { - return _.chain(ddata.devicestatus) - .filter(function isSameDeviceType(status) { - return status.device === deviceAndType.device && _.has(status, deviceAndType.type) - }) - .filter(function notInTheFuture(status) { - return status.mills <= time; - }) - .sortBy('mills') - .takeRight(10) - .value(); - }).value(); - - var merged = [].concat.apply([], rv); - - rv = _.chain(merged) - .filter(_.isObject) - .uniq('_id') - .sortBy('mills') - .value(); - - return rv; - - }; - - ddata.processDurations = function processDurations(treatments, keepzeroduration) { - - treatments = _.uniqBy(treatments, 'mills'); - - // cut temp basals by end events - // better to do it only on data update - var endevents = treatments.filter(function filterEnd(t) { - return !t.duration; - }); - - function cutIfInInterval(base, end) { - if (base.mills < end.mills && base.mills + times.mins(base.duration).msecs > end.mills) { - base.duration = times.msecs(end.mills - base.mills).mins; - if (end.profile) { - base.cuttedby = end.profile; - end.cutting = base.profile; - } - } - } - - // cut by end events - treatments.forEach(function allTreatments(t) { - if (t.duration) { - endevents.forEach(function allEndevents(e) { - cutIfInInterval(t, e); - }); - } - }); - - // cut by overlaping events - treatments.forEach(function allTreatments(t) { - if (t.duration) { - treatments.forEach(function allEndevents(e) { - cutIfInInterval(t, e); - }); - } - }); - - if (keepzeroduration) { - return treatments; - } else { - return treatments.filter(function filterEnd(t) { - return t.duration; - }); - } - }; - - ddata.processTreatments = function processTreatments(preserveOrignalTreatments) { - - // filter & prepare 'Site Change' events - ddata.sitechangeTreatments = ddata.treatments.filter(function filterSensor(t) { - return t.eventType.indexOf('Site Change') > -1; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - - // filter & prepare 'Insulin Change' events - ddata.insulinchangeTreatments = ddata.treatments.filter(function filterInsulin(t) { - return t.eventType.indexOf('Insulin Change') > -1; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - - // filter & prepare 'Pump Battery Change' events - ddata.batteryTreatments = ddata.treatments.filter(function filterSensor(t) { - return t.eventType.indexOf('Pump Battery Change') > -1; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - - // filter & prepare 'Sensor' events - ddata.sensorTreatments = ddata.treatments.filter(function filterSensor(t) { - return t.eventType.indexOf('Sensor') > -1; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - - // filter & prepare 'Profile Switch' events - var profileTreatments = ddata.treatments.filter(function filterProfiles(t) { - return t.eventType === 'Profile Switch'; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - if (preserveOrignalTreatments) - profileTreatments = _.cloneDeep(profileTreatments); - ddata.profileTreatments = ddata.processDurations(profileTreatments, true); - - // filter & prepare 'Combo Bolus' events - ddata.combobolusTreatments = ddata.treatments.filter(function filterComboBoluses(t) { - return t.eventType === 'Combo Bolus'; - }).sort(function(a, b) { - return a.mills > b.mills; - }); - - // filter & prepare temp basals - var tempbasalTreatments = ddata.treatments.filter(function filterBasals(t) { - return t.eventType && t.eventType.indexOf('Temp Basal') > -1; - }); - if (preserveOrignalTreatments) - tempbasalTreatments = _.cloneDeep(tempbasalTreatments); - ddata.tempbasalTreatments = ddata.processDurations(tempbasalTreatments, false); - - // filter temp target - var tempTargetTreatments = ddata.treatments.filter(function filterTargets(t) { - //check for a units being sent - if (t.units) { - if (t.units == 'mmol') { - //convert to mgdl - t.targetTop = t.targetTop * 18; - t.targetBottom = t.targetBottom * 18; - t.units = 'mg/dl'; - } - } - //if we have a temp target thats below 20, assume its mmol and convert to mgdl for safety. - if (t.targetTop < 20) { - t.targetTop = t.targetTop * 18; - t.units = 'mg/dl'; - } - if (t.targetBottom < 20) { - t.targetBottom = t.targetBottom * 18; - t.units = 'mg/dl'; - } - return t.eventType && t.eventType.indexOf('Temporary Target') > -1; - }); - if (preserveOrignalTreatments) - tempTargetTreatments = _.cloneDeep(tempTargetTreatments); - ddata.tempTargetTreatments = ddata.processDurations(tempTargetTreatments, false); - - }; - - return ddata; + return ddata; } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/lib/language.js b/lib/language.js index cfc2093f..b7c826d3 100644 --- a/lib/language.js +++ b/lib/language.js @@ -834,7 +834,6 @@ function init() { ,dk: 'Noter indeholder' ,fi: 'Merkinnät sisältävät' ,nb: 'Notater inneholder' - ,he: 'הערות מכילות' ,pl: 'Zawierają uwagi' ,ru: 'Примечания содержат' ,sk: 'Poznámky obsahujú' @@ -1460,7 +1459,6 @@ function init() { ,sv: 'temp basal måste vara synlig för denna rapport' ,de: 'temporäre Basalraten müssen für diesen Report sichtbar sein' ,fi: 'tämä raportti vaatii, että basaalien piirto on päällä' - ,he: 'חובה לאפשר רמה בזלית זמנית כדי לרות דוח זה' ,bg: 'временните базали трябва да са показани за да се покаже тази това' ,hr: 'temp bazali moraju biti prikazani kako bi se vidio ovaj izvještaj' ,he: 'חובה לאפשר רמה בזלית זמנית כדי לרות דוח זה' @@ -1469,7 +1467,6 @@ function init() { } ,'Weekly success' : { cs: 'Statistika po týdnech' - ,he: 'הצלחה שבועית' ,de: 'Wöchentlicher Erfolg' ,es: 'Resultados semanales' ,fr: 'Résultat hebdomadaire' @@ -1747,7 +1744,6 @@ function init() { cs: 'Normální' ,de: 'Normal' ,es: 'Normal' - ,he: 'נורמלי ' ,fr: 'Normale' ,el: 'Εντός Στόχου' ,pt: 'Normal' @@ -1871,7 +1867,6 @@ function init() { } ,'Glucose Percentile report' : { cs: 'Tabulka percentil glykémií' - ,he: 'דוח אחוזוני גלוקוזה' ,de: 'Glukose-Perzentil Bericht' ,es: 'Informe de percetiles de glucemia' ,fr: 'Rapport percentiles Glycémie' @@ -2196,7 +2191,6 @@ function init() { } ,'Weekly Success' : { cs: 'Týdenní úspěšnost' - ,he: 'הצלחה שבועית ' ,de: 'Wöchtlicher Erfolg' ,es: 'Resultados semanales' ,fr: 'Réussite hebdomadaire' @@ -2263,7 +2257,6 @@ function init() { ,dk: 'Anvender gemt API-nøgle' ,fi: 'Tallennettu salainen API-tarkiste käytössä' ,nb: 'Bruker lagret API nøkkel' - ,he: 'עורך אוכל' ,pl: 'Korzystając z zapisanego poufnego hasha API' ,ru: 'Применение сохраненного пароля API' ,sk: 'Používam uložený API hash heslo' @@ -2275,7 +2268,6 @@ function init() { } ,'No API secret hash stored yet. You need to enter API secret.' : { cs: 'Není uložený žádný hash API hesla. Musíte zadat API heslo.' - ,he: 'הכנס את סיסמת ממשק תכנות יישומים הסודית' ,de: 'Keine API-Prüfsumme gespeichert. Bitte API-Prüfsumme eingeben.' ,es: 'No se ha almacenado ningún hash todavía. Debe introducir su secreto API.' ,fr: 'Pas de secret API existant. Vous devez en entrer un.' @@ -2302,7 +2294,6 @@ function init() { } ,'Database loaded' : { cs: 'Databáze načtena' - ,he: 'אגר מידע נטען ' ,de: 'Datenbank geladen' ,es: 'Base de datos cargada' ,fr: 'Base de données chargée' @@ -2496,7 +2487,6 @@ function init() { ,pl: 'IG' ,ru: 'ГИ' ,sk: 'GI' - ,he: 'GI' ,nl: 'Glycemische index ' ,ko: '혈당 지수' ,tr: 'GI-Glisemik İndeks' @@ -2638,7 +2628,6 @@ function init() { ,ro: 'Cheia API trebuie să aibă mai mult de 12 caractere' ,bg: 'Вашата АPI парола трябва да е дълга поне 12 символа' ,hr: 'Vaš tajni API mora sadržavati barem 12 znakova' - ,he:' הסיסמא הסודית חייבת להיות באורך של 12 תווים לפחות' ,sv: 'Hemlig API-nyckel måsta innehålla 12 tecken' ,it: 'il vostro API secreto deve essere lungo almeno 12 caratteri' ,ja: 'APIシークレットは12文字以上の長さが必要です' @@ -2673,7 +2662,6 @@ function init() { ,nb: 'Ugyldig API nøkkel' ,pl: 'Błędny klucz API' ,ru: 'Плохой пароль API' - ,he: ' הסיסמא הסודית אינה חוקית' ,sk: 'Nesprávne API heslo' ,nl: 'Onjuist API wachtwoord' ,ko: '잘못된 API secret' @@ -2699,7 +2687,6 @@ function init() { ,fi: 'API salaisuus talletettu' ,nb: 'API nøkkel lagret' ,pl: 'Poufne klucz API zapisane' - ,he: ' הסיסמא הסודית נשמרה' ,ru: 'Хэш пароля API сохранен' ,sk: 'Hash API hesla uložený' ,nl: 'API wachtwoord opgeslagen' @@ -2750,7 +2737,6 @@ function init() { ,dk: 'Ikke indlæst' ,fi: 'Ei ladattu' ,nb: 'Ikke lest' - ,he: 'לא נטען' ,pl: 'Nie załadowany' ,ru: 'Не загружено' ,sk: 'Nenačítaný' @@ -2773,7 +2759,6 @@ function init() { ,sv: 'Födoämneseditor' ,it: 'NS - Database Alimenti' ,ja: '食事編集' - ,he: 'עורך מזון' ,dk: 'Mad editor' ,fi: 'Muokkaa ruokia' ,nb: 'Mat editor' @@ -2973,7 +2958,6 @@ function init() { ,ro: 'Cheia API' ,bg: 'Твоята API парола' ,hr: 'Vaš tajni API' - ,he: 'הסיסמא הסודית שלך' ,it: 'Il tuo API secreto' ,ja: 'あなたのAPI Secret' ,dk: 'Din API-nøgle' @@ -3005,7 +2989,6 @@ function init() { ,dk: 'Gemme hash på denne computer (brug kun på privat computer)' ,fi: 'Tallenna avain tälle tietokoneelle (käytä vain omalla tietokoneellasi)' ,nb: 'Lagre hash på denne pc (bruk kun på privat pc)' - ,he:'שמור סיסמא הסודית על המחשב ( יש להשתמש רק על מחשב פרטי)' ,pl: 'Zapisz na tym komputerze (korzystaj tylko na komputerach prywatnych)' ,ru: 'Сохранить хеш на этом ПК (только для личных компьютеров)' ,sk: 'Uložiť hash na tomto počítači (Používajte iba na súkromných počítačoch)' @@ -7692,7 +7675,7 @@ function init() { cs: 'Odstraňování záznamů ...' ,he: 'מוחק רשומות ... ' ,nb: 'Fjerner elementer...' - ,fr: 'Effacement d\événements...' + ,fr: 'Effacement dévénements...' ,ro: 'Se șterg înregistrările...' ,el: 'Αφαίρεση Εγγραφών' ,de: 'Entferne Einträge ...' @@ -7714,29 +7697,7 @@ function init() { ,zh_tw: '正在刪除記錄...' } ,'%1 records deleted' : { - cs: '%1 records deleted' - ,he: '%1 records deleted' - ,nb: '%1 records deleted' - ,fr: '%1 records deleted' - ,ro: '%1 records deleted' - ,el: '%1 records deleted' - ,de: '%1 records deleted' - ,es: '%1 records deleted' - ,dk: '%1 records deleted' - ,sv: '%1 records deleted' - ,bg: '%1 records deleted' - ,hr: 'obrisano %1 zapisa' - ,it: '%1 records deleted' - ,fi: '%1 records deleted' - ,pl: '%1 records deleted' - ,pt: '%1 records deleted' - ,ru: '%1 records deleted' - ,sk: '%1 records deleted' - ,nl: '%1 records deleted' - ,ko: '%1 records deleted' - ,tr: '%1 records deleted' - ,zh_cn: '%1 records deleted' - ,zh_tw: '%1 records deleted' + hr: 'obrisano %1 zapisa' } ,'Clean Mongo status database' : { cs: 'Vyčištění Mongo databáze statusů' @@ -7906,379 +7867,49 @@ function init() { ,zh_cn: '所有记录已经被清除' } ,'Delete all documents from devicestatus collection older than 30 days' : { - cs: 'Delete all documents from devicestatus collection older than 30 days' - ,he: 'Delete all documents from devicestatus collection older than 30 days' - ,nb: 'Delete all documents from devicestatus collection older than 30 days' - ,fr: 'Delete all documents from devicestatus collection older than 30 days' - ,ro: 'Delete all documents from devicestatus collection older than 30 days' - ,el: 'Delete all documents from devicestatus collection older than 30 days' - ,de: 'Delete all documents from devicestatus collection older than 30 days' - ,es: 'Delete all documents from devicestatus collection older than 30 days' - ,dk: 'Delete all documents from devicestatus collection older than 30 days' - ,sv: 'Delete all documents from devicestatus collection older than 30 days' - ,bg: 'Delete all documents from devicestatus collection older than 30 days' - ,hr: 'Obriši sve statuse starije od 30 dana' - ,it: 'Delete all documents from devicestatus collection older than 30 days' - ,fi: 'Delete all documents from devicestatus collection older than 30 days' - ,pl: 'Delete all documents from devicestatus collection older than 30 days' - ,pt: 'Delete all documents from devicestatus collection older than 30 days' - ,ru: 'Delete all documents from devicestatus collection older than 30 days' - ,sk: 'Delete all documents from devicestatus collection older than 30 days' - ,nl: 'Delete all documents from devicestatus collection older than 30 days' - ,ko: 'Delete all documents from devicestatus collection older than 30 days' - ,tr: 'Delete all documents from devicestatus collection older than 30 days' - ,zh_cn: 'Delete all documents from devicestatus collection older than 30 days' - ,zh_tw: 'Delete all documents from devicestatus collection older than 30 days' + hr: 'Obriši sve statuse starije od 30 dana' } ,'Number of Days to Keep:' : { - cs: 'Number of Days to Keep:' - ,he: 'Number of Days to Keep:' - ,nb: 'Number of Days to Keep:' - ,fr: 'Number of Days to Keep:' - ,ro: 'Number of Days to Keep:' - ,el: 'Number of Days to Keep:' - ,de: 'Number of Days to Keep:' - ,es: 'Number of Days to Keep:' - ,dk: 'Number of Days to Keep:' - ,sv: 'Number of Days to Keep:' - ,bg: 'Number of Days to Keep:' - ,hr: 'Broj dana za sačuvati:' - ,it: 'Number of Days to Keep:' - ,fi: 'Number of Days to Keep:' - ,pl: 'Number of Days to Keep:' - ,pt: 'Number of Days to Keep:' - ,ru: 'Number of Days to Keep:' - ,sk: 'Number of Days to Keep:' - ,nl: 'Number of Days to Keep:' - ,ko: 'Number of Days to Keep:' - ,tr: 'Number of Days to Keep:' - ,zh_cn: 'Number of Days to Keep:' - ,zh_tw: 'Number of Days to Keep:' + hr: 'Broj dana za sačuvati:' } ,'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' : { - cs: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,he: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,nb: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,fr: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,ro: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,el: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,de: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,es: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,dk: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,sv: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,bg: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,hr: 'Ovo uklanja sve statuse starije od 30 dana. Korisno kada se status baterije uploadera ne osvježava ispravno.' - ,it: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,fi: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,pl: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,pt: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,ru: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,sk: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,nl: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,ko: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,tr: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,zh_cn: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' - ,zh_tw: 'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' + hr: 'Ovo uklanja sve statuse starije od 30 dana. Korisno kada se status baterije uploadera ne osvježava ispravno.' } ,'Delete old documents from devicestatus collection?' : { - cs: 'Delete old documents from devicestatus collection?' - ,he: 'Delete old documents from devicestatus collection?' - ,nb: 'Delete old documents from devicestatus collection?' - ,fr: 'Delete old documents from devicestatus collection?' - ,ro: 'Delete old documents from devicestatus collection?' - ,el: 'Delete old documents from devicestatus collection?' - ,de: 'Delete old documents from devicestatus collection?' - ,es: 'Delete old documents from devicestatus collection?' - ,dk: 'Delete old documents from devicestatus collection?' - ,sv: 'Delete old documents from devicestatus collection?' - ,bg: 'Delete old documents from devicestatus collection?' - ,hr: 'Obriši stare statuse' - ,it: 'Delete old documents from devicestatus collection?' - ,fi: 'Delete old documents from devicestatus collection?' - ,pl: 'Delete old documents from devicestatus collection?' - ,pt: 'Delete old documents from devicestatus collection?' - ,ru: 'Delete old documents from devicestatus collection?' - ,sk: 'Delete old documents from devicestatus collection?' - ,nl: 'Delete old documents from devicestatus collection?' - ,ko: 'Delete old documents from devicestatus collection?' - ,tr: 'Delete old documents from devicestatus collection?' - ,zh_cn: 'Delete old documents from devicestatus collection?' - ,zh_tw: 'Delete old documents from devicestatus collection?' + hr: 'Obriši stare statuse' } ,'Clean Mongo entries (glucose entries) database' : { - cs: 'Clean Mongo entries (glucose entries) database' - ,he: 'Clean Mongo entries (glucose entries) database' - ,nb: 'Clean Mongo entries (glucose entries) database' - ,fr: 'Clean Mongo entries (glucose entries) database' - ,ro: 'Clean Mongo entries (glucose entries) database' - ,el: 'Clean Mongo entries (glucose entries) database' - ,de: 'Clean Mongo entries (glucose entries) database' - ,es: 'Clean Mongo entries (glucose entries) database' - ,dk: 'Clean Mongo entries (glucose entries) database' - ,sv: 'Clean Mongo entries (glucose entries) database' - ,bg: 'Clean Mongo entries (glucose entries) database' - ,hr: 'Obriši GUK zapise iz baze' - ,it: 'Clean Mongo entries (glucose entries) database' - ,fi: 'Clean Mongo entries (glucose entries) database' - ,pl: 'Clean Mongo entries (glucose entries) database' - ,pt: 'Clean Mongo entries (glucose entries) database' - ,ru: 'Clean Mongo entries (glucose entries) database' - ,sk: 'Clean Mongo entries (glucose entries) database' - ,nl: 'Clean Mongo entries (glucose entries) database' - ,ko: 'Clean Mongo entries (glucose entries) database' - ,tr: 'Clean Mongo entries (glucose entries) database' - ,zh_cn: 'Clean Mongo entries (glucose entries) database' - ,zh_tw: 'Clean Mongo entries (glucose entries) database' + hr: 'Obriši GUK zapise iz baze' } ,'Delete all documents from entries collection older than 180 days' : { - cs: 'Delete all documents from entries collection older than 180 days' - ,he: 'Delete all documents from entries collection older than 180 days' - ,nb: 'Delete all documents from entries collection older than 180 days' - ,fr: 'Delete all documents from entries collection older than 180 days' - ,ro: 'Delete all documents from entries collection older than 180 days' - ,el: 'Delete all documents from entries collection older than 180 days' - ,de: 'Delete all documents from entries collection older than 180 days' - ,es: 'Delete all documents from entries collection older than 180 days' - ,dk: 'Delete all documents from entries collection older than 180 days' - ,sv: 'Delete all documents from entries collection older than 180 days' - ,bg: 'Delete all documents from entries collection older than 180 days' - ,hr: 'Obriši sve zapise starije od 180 dana' - ,it: 'Delete all documents from entries collection older than 180 days' - ,fi: 'Delete all documents from entries collection older than 180 days' - ,pl: 'Delete all documents from entries collection older than 180 days' - ,pt: 'Delete all documents from entries collection older than 180 days' - ,ru: 'Delete all documents from entries collection older than 180 days' - ,sk: 'Delete all documents from entries collection older than 180 days' - ,nl: 'Delete all documents from entries collection older than 180 days' - ,ko: 'Delete all documents from entries collection older than 180 days' - ,tr: 'Delete all documents from entries collection older than 180 days' - ,zh_cn: 'Delete all documents from entries collection older than 180 days' - ,zh_tw: 'Delete all documents from entries collection older than 180 days' + hr: 'Obriši sve zapise starije od 180 dana' } ,'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' : { - cs: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,he: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,nb: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,fr: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ro: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,el: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,de: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,es: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,dk: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,sv: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,bg: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,hr: 'Ovo briše sve zapise starije od 180 dana. Korisno kada se status baterije uploadera ne osvježava.' - ,it: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,fi: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,pl: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,pt: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ru: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,sk: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,nl: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ko: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,tr: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,zh_cn: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,zh_tw: 'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' + hr: 'Ovo briše sve zapise starije od 180 dana. Korisno kada se status baterije uploadera ne osvježava.' } ,'Delete old documents' : { - cs: 'Delete old documents' - ,he: 'Delete old documents' - ,nb: 'Delete old documents' - ,fr: 'Delete old documents' - ,ro: 'Delete old documents' - ,el: 'Delete old documents' - ,de: 'Delete old documents' - ,es: 'Delete old documents' - ,dk: 'Delete old documents' - ,sv: 'Delete old documents' - ,bg: 'Delete old documents' - ,hr: 'Obriši stare zapise' - ,it: 'Delete old documents' - ,fi: 'Delete old documents' - ,pl: 'Delete old documents' - ,pt: 'Delete old documents' - ,ru: 'Delete old documents' - ,sk: 'Delete old documents' - ,nl: 'Delete old documents' - ,ko: 'Delete old documents' - ,tr: 'Delete old documents' - ,zh_cn: 'Delete old documents' - ,zh_tw: 'Delete old documents' + hr: 'Obriši stare zapise' } ,'Delete old documents from entries collection?' : { - cs: 'Delete old documents from entries collection?' - ,he: 'Delete old documents from entries collection?' - ,nb: 'Delete old documents from entries collection?' - ,fr: 'Delete old documents from entries collection?' - ,ro: 'Delete old documents from entries collection?' - ,el: 'Delete old documents from entries collection?' - ,de: 'Delete old documents from entries collection?' - ,es: 'Delete old documents from entries collection?' - ,dk: 'Delete old documents from entries collection?' - ,sv: 'Delete old documents from entries collection?' - ,bg: 'Delete old documents from entries collection?' - ,hr: 'Obriši stare zapise?' - ,it: 'Delete old documents from entries collection?' - ,fi: 'Delete old documents from entries collection?' - ,pl: 'Delete old documents from entries collection?' - ,pt: 'Delete old documents from entries collection?' - ,ru: 'Delete old documents from entries collection?' - ,sk: 'Delete old documents from entries collection?' - ,nl: 'Delete old documents from entries collection?' - ,ko: 'Delete old documents from entries collection?' - ,tr: 'Delete old documents from entries collection?' - ,zh_cn: 'Delete old documents from entries collection?' - ,zh_tw: 'Delete old documents from entries collection?' + hr: 'Obriši stare zapise?' } ,'%1 is not a valid number' : { - cs: '%1 is not a valid number' - ,he: '%1 is not a valid number' - ,nb: '%1 is not a valid number' - ,fr: '%1 is not a valid number' - ,ro: '%1 is not a valid number' - ,el: '%1 is not a valid number' - ,de: '%1 is not a valid number' - ,es: '%1 is not a valid number' - ,dk: '%1 is not a valid number' - ,sv: '%1 is not a valid number' - ,bg: '%1 is not a valid number' - ,hr: '%1 nije valjan broj' - ,it: '%1 is not a valid number' - ,fi: '%1 is not a valid number' - ,pl: '%1 is not a valid number' - ,pt: '%1 is not a valid number' - ,ru: '%1 is not a valid number' - ,sk: '%1 is not a valid number' - ,nl: '%1 is not a valid number' - ,ko: '%1 is not a valid number' - ,tr: '%1 is not a valid number' - ,zh_cn: '%1 is not a valid number' - ,zh_tw: '%1 is not a valid number' + hr: '%1 nije valjan broj' } ,'%1 is not a valid number - must be more than 2' : { - cs: '%1 is not a valid number - must be more than 2' - ,he: '%1 is not a valid number - must be more than 2' - ,nb: '%1 is not a valid number - must be more than 2' - ,fr: '%1 is not a valid number - must be more than 2' - ,ro: '%1 is not a valid number - must be more than 2' - ,el: '%1 is not a valid number - must be more than 2' - ,de: '%1 is not a valid number - must be more than 2' - ,es: '%1 is not a valid number - must be more than 2' - ,dk: '%1 is not a valid number - must be more than 2' - ,sv: '%1 is not a valid number - must be more than 2' - ,bg: '%1 is not a valid number - must be more than 2' - ,hr: '%1 nije valjan broj - mora biti veći od 2' - ,it: '%1 is not a valid number - must be more than 2' - ,fi: '%1 is not a valid number - must be more than 2' - ,pl: '%1 is not a valid number - must be more than 2' - ,pt: '%1 is not a valid number - must be more than 2' - ,ru: '%1 is not a valid number - must be more than 2' - ,sk: '%1 is not a valid number - must be more than 2' - ,nl: '%1 is not a valid number - must be more than 2' - ,ko: '%1 is not a valid number - must be more than 2' - ,tr: '%1 is not a valid number - must be more than 2' - ,zh_cn: '%1 is not a valid number - must be more than 2' - ,zh_tw: '%1 is not a valid number - must be more than 2' + hr: '%1 nije valjan broj - mora biti veći od 2' } ,'Clean Mongo treatments database' : { - cs: 'Clean Mongo treatments database' - ,he: 'Clean Mongo treatments database' - ,nb: 'Clean Mongo treatments database' - ,fr: 'Clean Mongo treatments database' - ,ro: 'Clean Mongo treatments database' - ,el: 'Clean Mongo treatments database' - ,de: 'Clean Mongo treatments database' - ,es: 'Clean Mongo treatments database' - ,dk: 'Clean Mongo treatments database' - ,sv: 'Clean Mongo treatments database' - ,bg: 'Clean Mongo treatments database' - ,hr: 'Obriši tretmane iz baze' - ,it: 'Clean Mongo treatments database' - ,fi: 'Clean Mongo treatments database' - ,pl: 'Clean Mongo treatments database' - ,pt: 'Clean Mongo treatments database' - ,ru: 'Clean Mongo treatments database' - ,sk: 'Clean Mongo treatments database' - ,nl: 'Clean Mongo treatments database' - ,ko: 'Clean Mongo treatments database' - ,tr: 'Clean Mongo treatments database' - ,zh_cn: 'Clean Mongo treatments database' - ,zh_tw: 'Clean Mongo treatments database' + hr: 'Obriši tretmane iz baze' } ,'Delete all documents from treatments collection older than 180 days' : { - cs: 'Delete all documents from treatments collection older than 180 days' - ,he: 'Delete all documents from treatments collection older than 180 days' - ,nb: 'Delete all documents from treatments collection older than 180 days' - ,fr: 'Delete all documents from treatments collection older than 180 days' - ,ro: 'Delete all documents from treatments collection older than 180 days' - ,el: 'Delete all documents from treatments collection older than 180 days' - ,de: 'Delete all documents from treatments collection older than 180 days' - ,es: 'Delete all documents from treatments collection older than 180 days' - ,dk: 'Delete all documents from treatments collection older than 180 days' - ,sv: 'Delete all documents from treatments collection older than 180 days' - ,bg: 'Delete all documents from treatments collection older than 180 days' - ,hr: 'Obriši tretmane starije od 180 dana iz baze' - ,it: 'Delete all documents from treatments collection older than 180 days' - ,fi: 'Delete all documents from treatments collection older than 180 days' - ,pl: 'Delete all documents from treatments collection older than 180 days' - ,pt: 'Delete all documents from treatments collection older than 180 days' - ,ru: 'Delete all documents from treatments collection older than 180 days' - ,sk: 'Delete all documents from treatments collection older than 180 days' - ,nl: 'Delete all documents from treatments collection older than 180 days' - ,ko: 'Delete all documents from treatments collection older than 180 days' - ,tr: 'Delete all documents from treatments collection older than 180 days' - ,zh_cn: 'Delete all documents from treatments collection older than 180 days' - ,zh_tw: 'Delete all documents from treatments collection older than 180 days' + hr: 'Obriši tretmane starije od 180 dana iz baze' } ,'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' : { - cs: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,he: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,nb: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,fr: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ro: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,el: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,de: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,es: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,dk: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,sv: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,bg: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,hr: 'Ovo briše sve tretmane starije od 180 dana iz baze. Korisno kada se status baterije uploadera ne osvježava.' - ,it: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,fi: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,pl: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,pt: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ru: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,sk: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,nl: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,ko: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,tr: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,zh_cn: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' - ,zh_tw: 'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' + hr: 'Ovo briše sve tretmane starije od 180 dana iz baze. Korisno kada se status baterije uploadera ne osvježava.' } ,'Delete old documents from treatments collection?' : { - cs: 'Delete old documents from treatments collection?' - ,he: 'Delete old documents from treatments collection?' - ,nb: 'Delete old documents from treatments collection?' - ,fr: 'Delete old documents from treatments collection?' - ,ro: 'Delete old documents from treatments collection?' - ,el: 'Delete old documents from treatments collection?' - ,de: 'Delete old documents from treatments collection?' - ,es: 'Delete old documents from treatments collection?' - ,dk: 'Delete old documents from treatments collection?' - ,sv: 'Delete old documents from treatments collection?' - ,bg: 'Delete old documents from treatments collection?' - ,hr: 'Obriši stare tretmane?' - ,it: 'Delete old documents from treatments collection?' - ,fi: 'Delete old documents from treatments collection?' - ,pl: 'Delete old documents from treatments collection?' - ,pt: 'Delete old documents from treatments collection?' - ,ru: 'Delete old documents from treatments collection?' - ,sk: 'Delete old documents from treatments collection?' - ,nl: 'Delete old documents from treatments collection?' - ,ko: 'Delete old documents from treatments collection?' - ,tr: 'Delete old documents from treatments collection?' - ,zh_cn: 'Delete old documents from treatments collection?' - ,zh_tw: 'Delete old documents from treatments collection?' + hr: 'Obriši stare tretmane?' } ,'Admin Tools' : { cs: 'Nástroje pro správu' @@ -10106,7 +9737,7 @@ function init() { } ,'Profile is going to be saved in newer format used in Nightscout 0.9.0 and above and will not be usable in older versions anymore.\nAre you sure?' : { cs: 'Profil bude uložen v novějším formátu používaném v Nightscoutu 0.9.0 a novějších. Již nebude použitelný se starší verzí.\nJste si jistý?' - ,he: 'הפרופיל עומד להישמר בתבנית חדשה יותר בשימוש ב- Nightscout 0.9.0 ומעלה ולא יהיה ניתן להשתמש בו בגרסאות ישנות יותר. \ האם אתה בטוח? ' + ,he: 'הפרופיל עומד להישמר בתבנית חדשה יותר בשימוש ב- Nightscout 0.9.0 ומעלה ולא יהיה ניתן להשתמש בו בגרסאות ישנות יותר. \n האם אתה בטוח? ' ,el: 'Το προφίλ πρόκειται να αποθηκευτεί με τη νέα του μορφή (έκδοση Nighscout 0.9.0 και πάνω) και δεν πρόκειται να μπορεί να χρησιμοποιηθεί σε παλαιότερες εκδόσεις. \nΕίστε σίγουροι?' ,fr: 'Le profil va être sauvegardé dans un nouveau format utilisé par Nightscout 0.9.0 et suivants, et il ne pourra plus être utilisé par les versions antérieures. \nÊtes-vous sûr?' ,ro: 'Profilul va fi salvat într-un format nou, folosit în Nightscout 0.9.0 și superior și nu va mai fi posibilă folosirea pentru versiunile mai vechi.\nSunteți de acord?' @@ -10130,7 +9761,7 @@ function init() { } ,'Wrong profile setting.\nNo profile defined to displayed time.\nRedirecting to profile editor to create new profile.' : { cs: 'Chybě nastavený profil.\nNení definovaný žádný platný profil k času zobrazení.\nProvádím přesměrování na editor profilu.' - ,he: 'הגדרת פרופיל שגוי. \ N פרופיל מוגדר לזמן המוצג. מפנה מחדש לעורך פרופיל כדי ליצור פרופיל חדש. ' + ,he: 'הגדרת פרופיל שגוי. \n פרופיל מוגדר לזמן המוצג. מפנה מחדש לעורך פרופיל כדי ליצור פרופיל חדש. ' ,el: 'Λάθος προφίλ. Παρακαλώ δημιουργήστε ένα νέο προφίλ' ,fr: 'Erreur de réglage de profil. \nAucun profil défini pour indiquer l\'heure. \nRedirection vers la création d\'un nouveau profil. ' ,de: 'Falsche Profileinstellung.\nKein Profil festgelegt zur angezeigten Zeit.\n Weiter zum Profileditor, um ein neues Profil zu erstellen.' @@ -10709,7 +10340,6 @@ function init() { ,nb: 'Hver enkelt rolle vil ha en eller flere rettigheter. *-rettigheten er wildcard. Rettigheter settes hierarkisk med : som separator.' ,fi: 'Jokaisella roolilla on yksi tai useampia oikeuksia. * on jokeri (tunnistuu kaikkina oikeuksina), oikeudet ovat hierarkia joka käyttää : merkkiä erottimena.' ,de: 'Jede Rolle hat eine oder mehrere Berechtigungen. Die * Berechtigung ist ein Platzhalter, Berechtigungen sind hierachrchisch mit : als Separator.' - ,sv: 'Hver rolle vil have en eller flere rettigheder. * er en joker, rettigheder sættes hierakisk med : som skilletegn.' ,es: 'Cada Rol tiene uno o más permisos. El permiso * es un marcador de posición y los permisos son jerárquicos con : como separador.' ,pt: 'Cada função terá uma ou mais permissões. A permissão * é um wildcard, permissões são uma hierarquia utilizando * como um separador.' ,sk: 'Každá rola má 1 alebo viac oprávnení. Oprávnenie * je zástupný znak, oprávnenia sú hierarchie používajúce : ako oddelovač.' @@ -11994,7 +11624,6 @@ function init() { ,sk: 'Nadbytok inzulínu o %1U viac ako je potrebné na dosiahnutie spodnej cieľovej hranice. Neráta sa so sacharidmi.' ,ko: '낮은 혈당 목표에 도달하기 위해 필요한 인슐린양보다 %1U의 인슐린 양이 초과 되었고 탄수화물 양이 초과되지 않았습니다.' ,it: 'L\'eccesso d\'insulina equivalente %1U più che necessari per raggiungere l\'obiettivo basso, non rappresentano i carboidrati.' - ,nl: 'Overschot insuline %1U meer dan nodig om het laag doel te bereiken, geen rekening gehouden met KH' ,tr: 'Fazla insülin: Karbonhidratları dikkate alınmadan, alt hedefe ulaşmak için gerekenden %1U\'den daha fazla' //??? ,zh_cn: '胰岛素超过至血糖下限目标所需剂量%1单位,不计算碳水化合物' , pl: 'Nadmiar insuliny, %1J więcej niż potrzeba, aby osiągnąć cel dolnej granicy, nie biorąc pod uwagę węglowodanów' @@ -12427,7 +12056,7 @@ function init() { ,sv: 'Applicerad' ,nb: 'Satt inn' ,fi: 'Asetettu' - ,es: 'Insertar' + ,es: 'Insertado' ,pt: 'Inserido' ,sk: 'Zavedený' ,ko: '삽입된' @@ -12453,7 +12082,7 @@ function init() { ,nb: 'Nål alder' ,fi: 'KIKÄ' ,pt: 'ICAT' - ,es: 'Carb.desde' + ,es: 'Cánula desde' ,sk: 'SET' ,ko: '주입세트사용기간' ,it: 'CAGE' @@ -12477,7 +12106,7 @@ function init() { ,nb: 'Aktive karbohydrater' ,fi: 'AH' ,pt: 'COB' - ,es: 'Carbohidratos activos' + ,es: 'Carb. activos' ,sk: 'SACH' ,ko: 'COB' ,it: 'COB' @@ -14490,6 +14119,7 @@ function init() { } if (options && options.params) { for (var i = 0; i < options.params.length; i++) { + // eslint-disable-next-line no-useless-escape var r = new RegExp('\%' + (i+1), 'g'); translated = translated.replace(r, options.params[i]); } diff --git a/lib/notifications.js b/lib/notifications.js index 8eb1f4eb..1a03ab87 100644 --- a/lib/notifications.js +++ b/lib/notifications.js @@ -15,7 +15,7 @@ var Alarm = function(level, group, label) { }; // list of alarms with their thresholds -var alarms = { }; +var alarms = {}; function init (env, ctx) { function notifications () { @@ -41,7 +41,7 @@ function init (env, ctx) { var sendClear = false; - for (var level = 1; level <=2; level++) { + for (var level = 1; level <= 2; level++) { var alarm = getAlarm(level, group); if (alarm.lastEmitTime) { console.info('auto acking ' + alarm.level, ' - ', group); @@ -51,7 +51,7 @@ function init (env, ctx) { } if (sendClear) { - var notify = {clear: true, title: 'All Clear', message: 'Auto ack\'d alarm(s)', group: group}; + var notify = { clear: true, title: 'All Clear', message: 'Auto ack\'d alarm(s)', group: group }; ctx.bus.emit('notification', notify); logEmitEvent(notify); } @@ -70,8 +70,8 @@ function init (env, ctx) { var requests = {}; - notifications.initRequests = function initRequests ( ) { - requests = { notifies: [] , snoozes: []}; + notifications.initRequests = function initRequests () { + requests = { notifies: [], snoozes: [] }; }; notifications.initRequests(); @@ -82,12 +82,12 @@ function init (env, ctx) { */ notifications.findHighestAlarm = function findHighestAlarm (group) { group = group || 'default'; - var filtered = _.filter(requests.notifies, {group: group}); - return _.find(filtered, {level: levels.URGENT}) || _.find(filtered, {level: levels.WARN}); + var filtered = _.filter(requests.notifies, { group: group }); + return _.find(filtered, { level: levels.URGENT }) || _.find(filtered, { level: levels.WARN }); }; - notifications.findUnSnoozeable = function findUnSnoozeable ( ) { - return _.filter(requests.notifies, function (notify) { + notifications.findUnSnoozeable = function findUnSnoozeable () { + return _.filter(requests.notifies, function(notify) { return notify.level <= levels.INFO || notify.isAnnouncement; }); }; @@ -95,7 +95,7 @@ function init (env, ctx) { notifications.snoozedBy = function snoozedBy (notify) { if (notify.isAnnouncement) { return false; } - var filtered = _.filter(requests.snoozes, {group: notify.group}); + var filtered = _.filter(requests.snoozes, { group: notify.group }); if (_.isEmpty(filtered)) { return false; } @@ -107,13 +107,8 @@ function init (env, ctx) { return _.last(sorted); }; - notifications.registerGroup = function registerGroup (group) { - if (groups.indexOf(group) < 0) { - groups.push(group); - } - }; - notifications.requestNotify = function requestNotify (notify) { + // eslint-disable-next-line no-prototype-builtins if (!notify.hasOwnProperty('level') || !notify.title || !notify.message || !notify.plugin) { console.error(new Error('Unable to request notification, since the notify isn\'t complete: ' + JSON.stringify(notify))); return; @@ -135,7 +130,7 @@ function init (env, ctx) { requests.snoozes.push(snooze); }; - notifications.process = function process ( ) { + notifications.process = function process () { var notifyGroups = _.map(requests.notifies, function eachNotify (notify) { return notify.group; @@ -205,7 +200,7 @@ function init (env, ctx) { }; - function ifTestModeThen(callback) { + function ifTestModeThen (callback) { if (env.testMode) { return callback(); } else { @@ -213,15 +208,15 @@ function init (env, ctx) { } } - notifications.resetStateForTests = function resetStateForTests ( ) { - ifTestModeThen(function doResetStateForTests ( ) { + notifications.resetStateForTests = function resetStateForTests () { + ifTestModeThen(function doResetStateForTests () { console.info('resetting notifications state for tests'); alarms = {}; }); }; notifications.getAlarmForTests = function getAlarmForTests (level, group) { - return ifTestModeThen(function doResetStateForTests ( ) { + return ifTestModeThen(function doResetStateForTests () { group = group || 'default'; var alarm = getAlarm(level, group); console.info('got alarm for tests: ', alarm); @@ -249,7 +244,7 @@ function init (env, ctx) { }; } - function logEmitEvent(notify) { + function logEmitEvent (notify) { var type = notify.level >= levels.WARN ? 'ALARM' : (notify.clear ? 'ALL CLEAR' : 'NOTIFICATION'); console.info([ logTimestamp() + '\tEMITTING ' + type + ':' @@ -257,7 +252,7 @@ function init (env, ctx) { ].join('\n')); } - function logSnoozingEvent(highestAlarm, snoozedBy) { + function logSnoozingEvent (highestAlarm, snoozedBy) { console.info([ logTimestamp() + '\tSNOOZING ALARM:' , ' ' + JSON.stringify(notifyToView(highestAlarm)) @@ -267,11 +262,11 @@ function init (env, ctx) { } //TODO: we need a common logger, but until then... - function logTimestamp ( ) { + function logTimestamp () { return (new Date).toISOString(); } return notifications(); } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index c440f613..e25a2b36 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -15,6 +15,7 @@ var AR = [-0.723, 1.716]; //TODO: move this to css var AR2_COLOR = 'cyan'; +// eslint-disable-next-line no-unused-vars function init (ctx) { var ar2 = { @@ -23,7 +24,7 @@ function init (ctx) { , pluginType: 'forecast' }; - function buildTitle(prop, sbx) { + function buildTitle (prop, sbx) { var rangeLabel = prop.eventName ? sbx.translate(prop.eventName, { ci: true }).toUpperCase() : sbx.translate('Check BG'); var title = sbx.levels.toDisplay(prop.level) + ', ' + rangeLabel; @@ -35,7 +36,7 @@ function init (ctx) { } ar2.setProperties = function setProperties (sbx) { - sbx.offerProperty('ar2', function setAR2 ( ) { + sbx.offerProperty('ar2', function setAR2 () { var prop = { forecast: ar2.forecast(sbx) @@ -49,7 +50,7 @@ function init (ctx) { } var predicted = prop.forecast && prop.forecast.predicted; - var scaled = predicted && _.map(predicted, function(p) { return sbx.scaleEntry(p) } ); + var scaled = predicted && _.map(predicted, function(p) { return sbx.scaleEntry(p) }); if (scaled && scaled.length >= 3) { prop.displayLine = 'BG 15m: ' + scaled[2] + ' ' + sbx.unitsLabel; @@ -106,8 +107,8 @@ function init (ctx) { return result; }; - ar2.updateVisualisation = function updateVisualisation(sbx) { - sbx.pluginBase.addForecastPoints(ar2.forecastCone(sbx), {type: 'ar2', label: 'AR2 Forecast'}); + ar2.updateVisualisation = function updateVisualisation (sbx) { + sbx.pluginBase.addForecastPoints(ar2.forecastCone(sbx), { type: 'ar2', label: 'AR2 Forecast' }); }; ar2.forecastCone = function forecastCone (sbx) { @@ -118,7 +119,7 @@ function init (ctx) { var coneFactor = getConeFactor(sbx); - function pushConePoints(result, step) { + function pushConePoints (result, step) { var next = incrementAR2(result); //offset from points so they are at a unique time @@ -172,8 +173,8 @@ function init (ctx) { ar2.alexa = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['ar2 forecast', 'forecast'] + , routableSlot: 'metric' + , slots: ['ar2 forecast', 'forecast'] , intentHandler: alexaAr2Handler }] }; @@ -181,7 +182,7 @@ function init (ctx) { return ar2; } -function checkForecast(forecast, sbx) { +function checkForecast (forecast, sbx) { var result = undefined; if (forecast && forecast.avgLoss > URGENT_THRESHOLD) { @@ -199,7 +200,7 @@ function checkForecast(forecast, sbx) { } function selectEventType (prop, sbx) { - var predicted = prop.forecast && _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) } ); + var predicted = prop.forecast && _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) }); var in20mins = predicted && predicted.length >= 4 ? predicted[3] : undefined; @@ -239,7 +240,7 @@ function getConeFactor (sbx) { return value; } -function okToForecast(sbx) { +function okToForecast (sbx) { var bgnow = sbx.properties.bgnow; var delta = sbx.properties.delta; @@ -273,7 +274,7 @@ function incrementAR2 (result) { }; } -function pushPoint(result) { +function pushPoint (result) { var next = incrementAR2(result); next.points.push(ar2Point( @@ -284,8 +285,7 @@ function pushPoint(result) { return next; } - -function ar2Point(next, options) { +function ar2Point (next, options) { var step = options.step || 0; var coneFactor = options.coneFactor || 0; var offset = options.offset || 0; @@ -301,16 +301,15 @@ function ar2Point(next, options) { }; } - function buildDebug (prop, sbx) { return prop.forecast && { forecast: { avgLoss: prop.forecast.avgLoss - , predicted: _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) }).join(', ') + , predicted: _.map(prop.forecast.predicted, function(p) { return sbx.scaleEntry(p) }).join(', ') } }; } -function log10(val) { return Math.log(val) / Math.LN10; } +function log10 (val) { return Math.log(val) / Math.LN10; } module.exports = init; diff --git a/lib/plugins/careportal.js b/lib/plugins/careportal.js index 1e53d03b..2d65e1c9 100644 --- a/lib/plugins/careportal.js +++ b/lib/plugins/careportal.js @@ -8,6 +8,7 @@ function init() { , pluginType: 'drawer' }; + // eslint-disable-next-line no-unused-vars careportal.getEventTypes = function getEventTypes (sbx) { //TODO: use sbx and new CAREPORTAL_EVENTTYPE_GROUPS="core temps combo dad sensor site etc" diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index 3858e794..bc769197 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -4,7 +4,7 @@ var _ = require('lodash') , moment = require('moment') , times = require('../times'); -function init(ctx) { +function init (ctx) { var translate = ctx.language.translate; var iob = require('./iob')(ctx); @@ -16,15 +16,15 @@ function init(ctx) { cob.RECENCY_THRESHOLD = times.mins(30).msecs; - cob.setProperties = function setProperties(sbx) { - sbx.offerProperty('cob', function setCOB ( ) { + cob.setProperties = function setProperties (sbx) { + sbx.offerProperty('cob', function setCOB () { return cob.cobTotal(sbx.data.treatments, sbx.data.devicestatus, sbx.data.profile, sbx.time); }); }; - cob.cobTotal = function cobTotal(treatments, devicestatus, profile, time, spec_profile) { + cob.cobTotal = function cobTotal (treatments, devicestatus, profile, time, spec_profile) { - if (!profile || !profile.hasData()) { + if (!profile || !profile.hasData()) { console.warn('For the COB plugin to function you need a treatment profile'); return {}; } @@ -55,7 +55,7 @@ function init(ctx) { return addDisplay(result); }; - function addDisplay(cob) { + function addDisplay (cob) { if (_.isEmpty(cob) || cob.cob === undefined) { return {}; } @@ -82,7 +82,7 @@ function init(ctx) { var recentMills = time - cob.RECENCY_THRESHOLD; return _.chain(devicestatus) - .filter(function (cobStatus) { + .filter(function(cobStatus) { return cobStatus.mills <= futureMills && cobStatus.mills >= recentMills; }) .map(cob.fromDeviceStatus) @@ -95,7 +95,7 @@ function init(ctx) { cob.COBDeviceStatusesInTimeRange = function COBDeviceStatusesInTimeRange (devicestatus, from, to) { return _.chain(devicestatus) - .filter(function (cobStatus) { + .filter(function(cobStatus) { return cobStatus.mills > from && cobStatus.mills < to; }) .map(cob.fromDeviceStatus) @@ -104,7 +104,7 @@ function init(ctx) { .value(); }; - cob.fromDeviceStatus = function fromDeviceStatus(devicestatusEntry) { + cob.fromDeviceStatus = function fromDeviceStatus (devicestatusEntry) { var cobObj; if (_.get(devicestatusEntry, 'openaps') !== undefined) { @@ -140,7 +140,7 @@ function init(ctx) { cob: lastCOB , source: 'OpenAPS' , device: devicestatusEntry.device - , mills: lastMoment.valueOf( ) + , mills: lastMoment.valueOf() }; } else if (_.get(devicestatusEntry, 'loop.cob') !== undefined) { cobObj = devicestatusEntry.loop.cob; @@ -148,7 +148,7 @@ function init(ctx) { cob: cobObj.cob , source: 'Loop' , device: devicestatusEntry.device - , mills: moment(cobObj.timestamp).valueOf( ) + , mills: moment(cobObj.timestamp).valueOf() }; } else { return {}; @@ -164,7 +164,7 @@ function init(ctx) { var isDecaying = 0; var lastDecayedBy = 0; - _.each(treatments, function eachTreatment(treatment) { + _.each(treatments, function eachTreatment (treatment) { if (treatment.carbs && treatment.mills < time) { lastCarbs = treatment; var cCalc = cob.cobCalc(treatment, profile, lastDecayedBy, time, spec_profile); @@ -175,7 +175,7 @@ function init(ctx) { var actEnd = iob.calcTotal(treatments, devicestatus, profile, cCalc.decayedBy, spec_profile).activity; var avgActivity = (actStart + actEnd) / 2; // units: g = BG * scalar / BG / U * g / U - var delayedCarbs = ( avgActivity * liverSensRatio / profile.getSensitivity(treatment.mills, spec_profile) ) * profile.getCarbRatio(treatment.mills, spec_profile); + var delayedCarbs = (avgActivity * liverSensRatio / profile.getSensitivity(treatment.mills, spec_profile)) * profile.getCarbRatio(treatment.mills, spec_profile); var delayMinutes = Math.round(delayedCarbs / profile.getCarbAbsorptionRate(treatment.mills, spec_profile) * 60); if (delayMinutes > 0) { cCalc.decayedBy.setMinutes(cCalc.decayedBy.getMinutes() + delayMinutes); @@ -211,7 +211,7 @@ function init(ctx) { }; }; - cob.carbImpact = function carbImpact(rawCarbImpact, insulinImpact) { + cob.carbImpact = function carbImpact (rawCarbImpact, insulinImpact) { var liverSensRatio = 1.0; var liverCarbImpactMax = 0.7; var liverCarbImpact = Math.min(liverCarbImpactMax, liverSensRatio * insulinImpact); @@ -219,12 +219,12 @@ function init(ctx) { var netCarbImpact = Math.max(0, rawCarbImpact - liverCarbImpact); var totalImpact = netCarbImpact - insulinImpact; return { - netCarbImpact: netCarbImpact, - totalImpact: totalImpact + netCarbImpact: netCarbImpact + , totalImpact: totalImpact }; }; - cob.cobCalc = function cobCalc(treatment, profile, lastDecayedBy, time, spec_profile) { + cob.cobCalc = function cobCalc (treatment, profile, lastDecayedBy, time, spec_profile) { var delay = 20; var isDecaying = 0; @@ -232,7 +232,7 @@ function init(ctx) { if (treatment.carbs) { var carbTime = new Date(treatment.mills); - + var carbs_hr = profile.getCarbAbsorptionRate(treatment.mills, spec_profile); var carbs_min = carbs_hr / 60; @@ -241,31 +241,28 @@ function init(ctx) { decayedBy.setMinutes(decayedBy.getMinutes() + Math.max(delay, minutesleft) + treatment.carbs / carbs_min); if (delay > minutesleft) { initialCarbs = parseInt(treatment.carbs); - } - else { + } else { initialCarbs = parseInt(treatment.carbs) + minutesleft * carbs_min; } var startDecay = new Date(carbTime); startDecay.setMinutes(carbTime.getMinutes() + delay); if (time < lastDecayedBy || time > startDecay) { isDecaying = 1; - } - else { + } else { isDecaying = 0; } return { - initialCarbs: initialCarbs, - decayedBy: decayedBy, - isDecaying: isDecaying, - carbTime: carbTime + initialCarbs: initialCarbs + , decayedBy: decayedBy + , isDecaying: isDecaying + , carbTime: carbTime }; - } - else { + } else { return ''; } }; - cob.updateVisualisation = function updateVisualisation(sbx) { + cob.updateVisualisation = function updateVisualisation (sbx) { var prop = sbx.properties.cob; @@ -273,16 +270,16 @@ function init(ctx) { var displayCob = Math.round(prop.cob * 10) / 10; - var info = [ ]; + var info = []; if (prop.treatmentCOB !== undefined && prop.treatmentCOB.cob) { - info.push({label: translate('Careportal COB'), value: Math.round(prop.treatmentCOB.cob * 10) / 10}); + info.push({ label: translate('Careportal COB'), value: Math.round(prop.treatmentCOB.cob * 10) / 10 }); } var lastCarbs = prop.lastCarbs || (prop.treatmentCOB && prop.treatmentCOB.lastCarbs); if (lastCarbs) { var when = new Date(lastCarbs.mills).toLocaleString(); var amount = lastCarbs.carbs + 'g'; - info.push({label: translate('Last Carbs'), value: amount + ' @ ' + when}); + info.push({ label: translate('Last Carbs'), value: amount + ' @ ' + when }); } sbx.pluginBase.updatePillText(sbx, { @@ -305,8 +302,8 @@ function init(ctx) { cob.alexa = { intentHandlers: [{ intent: 'MetricNow' - , routableSlot:'metric' - , slots:['cob', 'carbs on board', 'carbohydrates on board'] + , routableSlot: 'metric' + , slots: ['cob', 'carbs on board', 'carbohydrates on board'] , intentHandler: alexaCOBHandler }] }; diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 9e81bae3..5970c168 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -7,12 +7,12 @@ var _get = require('lodash/get'); var _isArray = require('lodash/isArray'); var _map = require('lodash/map'); -function init(ctx) { +function init (ctx) { - var allPlugins = [], - enabledPlugins = []; + var allPlugins = [] + , enabledPlugins = []; - function plugins(name) { + function plugins (name) { if (name) { return _find(allPlugins, { name: name @@ -75,18 +75,18 @@ function init(ctx) { , require('./basalprofile')(ctx) ]; - plugins.registerServerDefaults = function registerServerDefaults() { + plugins.registerServerDefaults = function registerServerDefaults () { plugins.register(serverDefaultPlugins); return plugins; }; - plugins.registerClientDefaults = function registerClientDefaults() { + plugins.registerClientDefaults = function registerClientDefaults () { plugins.register(clientDefaultPlugins); return plugins; }; - plugins.register = function register(all) { - _each(all, function eachPlugin(plugin) { + plugins.register = function register (all) { + _each(all, function eachPlugin (plugin) { allPlugins.push(plugin); }); @@ -94,58 +94,57 @@ function init(ctx) { var enable = _get(ctx, 'settings.enable'); - function isEnabled(plugin) { + function isEnabled (plugin) { //TODO: unify client/server env/app return enable && enable.indexOf(plugin.name) > -1; } - _each(allPlugins, function eachPlugin(plugin) { + _each(allPlugins, function eachPlugin (plugin) { plugin.enabled = isEnabled(plugin); if (plugin.enabled) { enabledPlugins.push(plugin); } }); - }; - plugins.isPluginEnabled = function isPluginEnabled(pluginName) { - var p = _.find(enabledPlugins, 'name', pluginName); + plugins.isPluginEnabled = function isPluginEnabled (pluginName) { + var p = _find(enabledPlugins, 'name', pluginName); return (p !== null); } - plugins.getPlugin = function getPlugin(pluginName) { - return _.find(enabledPlugins, 'name', pluginName); + plugins.getPlugin = function getPlugin (pluginName) { + return _find(enabledPlugins, 'name', pluginName); } - plugins.eachPlugin = function eachPlugin(f) { + plugins.eachPlugin = function eachPlugin (f) { _each(allPlugins, f); }; - plugins.eachEnabledPlugin = function eachEnabledPlugin(f) { + plugins.eachEnabledPlugin = function eachEnabledPlugin (f) { _each(enabledPlugins, f); }; //these plugins are either always on or have custom settings plugins.specialPlugins = 'ar2 bgnow delta direction timeago upbat rawbg errorcodes profile'; - plugins.shownPlugins = function (sbx) { - return _filter(enabledPlugins, function filterPlugins(plugin) { + plugins.shownPlugins = function(sbx) { + return _filter(enabledPlugins, function filterPlugins (plugin) { return plugins.specialPlugins.indexOf(plugin.name) > -1 || (sbx && sbx.showPlugins && sbx.showPlugins.indexOf(plugin.name) > -1); }); }; - plugins.eachShownPlugins = function eachShownPlugins(sbx, f) { + plugins.eachShownPlugins = function eachShownPlugins (sbx, f) { _each(plugins.shownPlugins(sbx), f); }; - plugins.hasShownType = function hasShownType(pluginType, sbx) { - return _find(plugins.shownPlugins(sbx), function findWithType(plugin) { + plugins.hasShownType = function hasShownType (pluginType, sbx) { + return _find(plugins.shownPlugins(sbx), function findWithType (plugin) { return plugin.pluginType === pluginType; }) !== undefined; }; - plugins.setProperties = function setProperties(sbx) { - plugins.eachEnabledPlugin(function eachPlugin(plugin) { + plugins.setProperties = function setProperties (sbx) { + plugins.eachEnabledPlugin(function eachPlugin (plugin) { if (plugin.setProperties) { try { plugin.setProperties(sbx.withExtendedSettings(plugin)); @@ -156,8 +155,8 @@ function init(ctx) { }); }; - plugins.checkNotifications = function checkNotifications(sbx) { - plugins.eachEnabledPlugin(function eachPlugin(plugin) { + plugins.checkNotifications = function checkNotifications (sbx) { + plugins.eachEnabledPlugin(function eachPlugin (plugin) { if (plugin.checkNotifications) { try { plugin.checkNotifications(sbx.withExtendedSettings(plugin)); @@ -168,8 +167,8 @@ function init(ctx) { }); }; - plugins.visualizeAlarm = function visualizeAlarm(sbx, alarm, alarmMessage) { - plugins.eachShownPlugins(sbx, function eachPlugin(plugin) { + plugins.visualizeAlarm = function visualizeAlarm (sbx, alarm, alarmMessage) { + plugins.eachShownPlugins(sbx, function eachPlugin (plugin) { if (plugin.visualizeAlarm) { try { plugin.visualizeAlarm(sbx.withExtendedSettings(plugin), alarm, alarmMessage); @@ -180,8 +179,8 @@ function init(ctx) { }); }; - plugins.updateVisualisations = function updateVisualisations(sbx) { - plugins.eachShownPlugins(sbx, function eachPlugin(plugin) { + plugins.updateVisualisations = function updateVisualisations (sbx) { + plugins.eachShownPlugins(sbx, function eachPlugin (plugin) { if (plugin.updateVisualisation) { try { plugin.updateVisualisation(sbx.withExtendedSettings(plugin)); @@ -192,9 +191,9 @@ function init(ctx) { }); }; - plugins.getAllEventTypes = function getAllEventTypes(sbx) { + plugins.getAllEventTypes = function getAllEventTypes (sbx) { var all = []; - plugins.eachEnabledPlugin(function eachPlugin(plugin) { + plugins.eachEnabledPlugin(function eachPlugin (plugin) { if (plugin.getEventTypes) { var eventTypes = plugin.getEventTypes(sbx.withExtendedSettings(plugin)); if (_isArray(eventTypes)) { @@ -206,15 +205,15 @@ function init(ctx) { return all; }; - plugins.enabledPluginNames = function enabledPluginNames() { - return _map(enabledPlugins, function mapped(plugin) { + plugins.enabledPluginNames = function enabledPluginNames () { + return _map(enabledPlugins, function mapped (plugin) { return plugin.name; }).join(' '); }; - plugins.extendedClientSettings = function extendedClientSettings(allExtendedSettings) { + plugins.extendedClientSettings = function extendedClientSettings (allExtendedSettings) { var clientSettings = {}; - _each(clientDefaultPlugins, function eachClientPlugin(plugin) { + _each(clientDefaultPlugins, function eachClientPlugin (plugin) { clientSettings[plugin.name] = allExtendedSettings[plugin.name]; }); @@ -228,4 +227,4 @@ function init(ctx) { } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index 9ac9c3d7..fc8dcbb3 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -7,7 +7,7 @@ var levels = require('../levels'); // var ALL_STATUS_FIELDS = ['status-symbol', 'status-label', 'iob', 'freq', 'rssi']; Unused variable -function init(ctx) { +function init (ctx) { var utils = require('../utils')(ctx); var loop = { @@ -18,7 +18,7 @@ function init(ctx) { var firstPrefs = true; - loop.getPrefs = function getPrefs(sbx) { + loop.getPrefs = function getPrefs (sbx) { var prefs = { warn: sbx.extendedSettings.warn ? sbx.extendedSettings.warn : 30 @@ -35,7 +35,7 @@ function init(ctx) { }; loop.setProperties = function setProperties (sbx) { - sbx.offerProperty('loop', function setLoop ( ) { + sbx.offerProperty('loop', function setLoop () { return loop.analyzeData(sbx); }); }; @@ -45,14 +45,14 @@ function init(ctx) { var recentMills = sbx.time - times.hours(recentHours).msecs; var recentData = _.chain(sbx.data.devicestatus) - .filter(function (status) { + .filter(function(status) { return ('loop' in status) && sbx.entryMills(status) <= sbx.time && sbx.entryMills(status) >= recentMills; - }).value( ); + }).value(); var prefs = loop.getPrefs(sbx); var recent = moment(sbx.time).subtract(prefs.warn / 2, 'minutes'); - function getDisplayForStatus (status) { + function getDisplayForStatus (status) { var desc = { symbol: '⚠' @@ -146,7 +146,7 @@ function init(ctx) { return result; }; - loop.checkNotifications = function checkNotifications(sbx) { + loop.checkNotifications = function checkNotifications (sbx) { var prefs = loop.getPrefs(sbx); if (!prefs.enableAlerts) { return; } @@ -182,9 +182,9 @@ function init(ctx) { return (value != null) ? prefix + value : ''; } - var events = [ ]; + var events = []; - function addRecommendedTempBasal() { + function addRecommendedTempBasal () { if (prop.lastLoop && prop.lastLoop.recommendedTempBasal) { var recommendedTempBasal = prop.lastLoop.recommendedTempBasal; @@ -196,7 +196,7 @@ function init(ctx) { valueParts = concatIOB(valueParts); valueParts = concatCOB(valueParts); - valueParts = concatEventualBG (valueParts); + valueParts = concatEventualBG(valueParts); valueParts = concatRecommendedBolus(valueParts); events.push({ @@ -206,48 +206,48 @@ function init(ctx) { } } - function addRSSI() { - + function addRSSI () { + var mostRecent = ""; var pumpRSSI = ""; var bleRSSI = ""; var reportRSSI = ""; - + _.forEach(sbx.data.devicestatus, function(entry) { - + if (entry.radioAdapter) { var entryMoment = moment(entry.created_at); - - if (mostRecent == "") { - mostRecent = entryMoment; - if (entry.radioAdapter.pumpRSSI) { - pumpRSSI = entry.radioAdapter.pumpRSSI; - } - if (entry.radioAdapter.RSSI) { - bleRSSI = entry.radioAdapter.RSSI; - } - } - - if (mostRecent < entryMoment) { - mostRecent = entryMoment; - if (entry.radioAdapter.pumpRSSI) { - pumpRSSI = entry.radioAdapter.pumpRSSI; - } - if (entry.radioAdapter.RSSI) { - bleRSSI = entry.radioAdapter.RSSI; - } - } - } + + if (mostRecent == "") { + mostRecent = entryMoment; + if (entry.radioAdapter.pumpRSSI) { + pumpRSSI = entry.radioAdapter.pumpRSSI; + } + if (entry.radioAdapter.RSSI) { + bleRSSI = entry.radioAdapter.RSSI; + } + } + + if (mostRecent < entryMoment) { + mostRecent = entryMoment; + if (entry.radioAdapter.pumpRSSI) { + pumpRSSI = entry.radioAdapter.pumpRSSI; + } + if (entry.radioAdapter.RSSI) { + bleRSSI = entry.radioAdapter.RSSI; + } + } + } }); - + if (bleRSSI != "") { - reportRSSI = "BLE RSSI: " + bleRSSI + " "; + reportRSSI = "BLE RSSI: " + bleRSSI + " "; } - + if (pumpRSSI != "") { - reportRSSI = reportRSSI + "Pump RSSI: " + pumpRSSI; + reportRSSI = reportRSSI + "Pump RSSI: " + pumpRSSI; } - + if (reportRSSI != "") { events.push({ time: mostRecent @@ -256,21 +256,21 @@ function init(ctx) { } } - - function addLastEnacted() { + + function addLastEnacted () { if (prop.lastEnacted) { var canceled = prop.lastEnacted.rate === 0 && prop.lastEnacted.duration === 0; var valueParts = [ - , 'Temp Basal' + (canceled ? ' Canceled' : ' Started') + '' + 'Temp Basal' + (canceled ? ' Canceled' : ' Started') + '' , canceled ? '' : ' ' + prop.lastEnacted.rate.toFixed(2) + 'U/hour for ' + prop.lastEnacted.duration + 'm' , valueString(', ', prop.lastEnacted.reason) ]; valueParts = concatIOB(valueParts); valueParts = concatCOB(valueParts); - valueParts = concatEventualBG (valueParts); - valueParts = concatRecommendedBolus(valueParts); + valueParts = concatEventualBG(valueParts); + valueParts = concatRecommendedBolus(valueParts); events.push({ time: prop.lastEnacted.moment @@ -284,7 +284,9 @@ function init(ctx) { var iob = prop.lastLoop.iob; valueParts = valueParts.concat([ ', IOB: ' + , sbx.roundInsulinForDisplayFormat(iob.iob) + 'U' + , iob.basaliob ? ', Basal IOB ' + sbx.roundInsulinForDisplayFormat(iob.basaliob) + 'U' : '' ]); } @@ -294,7 +296,6 @@ function init(ctx) { function concatCOB (valueParts) { if (prop.lastLoop && prop.lastLoop.cob) { - var cob = prop.lastLoop.cob; var cob = prop.lastLoop.cob.cob; cob = Math.round(cob); valueParts = valueParts.concat([ @@ -309,28 +310,28 @@ function init(ctx) { function concatEventualBG (valueParts) { if (prop.lastLoop && prop.lastLoop.predicted) { var predictedBGvalues = prop.lastLoop.predicted.values; - var eventualBG = predictedBGvalues[predictedBGvalues.length-1]; - var maxBG = Math.max.apply(null,predictedBGvalues); - var minBG = Math.min.apply(null,predictedBGvalues); + var eventualBG = predictedBGvalues[predictedBGvalues.length - 1]; + var maxBG = Math.max.apply(null, predictedBGvalues); + var minBG = Math.min.apply(null, predictedBGvalues); var eventualBGscaled = sbx.settings.units === 'mmol' ? - sbx.roundBGToDisplayFormat(sbx.scaleMgdl(eventualBG)) : eventualBG; - var maxBGscaled = sbx.settings.units === 'mmol' ? - sbx.roundBGToDisplayFormat(sbx.scaleMgdl(maxBG)) : maxBG; - var minBGscaled = sbx.settings.units === 'mmol' ? - sbx.roundBGToDisplayFormat(sbx.scaleMgdl(minBG)) : minBG; + sbx.roundBGToDisplayFormat(sbx.scaleMgdl(eventualBG)) : eventualBG; + var maxBGscaled = sbx.settings.units === 'mmol' ? + sbx.roundBGToDisplayFormat(sbx.scaleMgdl(maxBG)) : maxBG; + var minBGscaled = sbx.settings.units === 'mmol' ? + sbx.roundBGToDisplayFormat(sbx.scaleMgdl(minBG)) : minBG; valueParts = valueParts.concat([ ', Predicted Min-Max BG: ' , minBGscaled , '-' , maxBGscaled - ,', Eventual BG: ' + , ', Eventual BG: ' , eventualBGscaled ]); } return valueParts; - } + } function concatRecommendedBolus (valueParts) { if (prop.lastLoop && prop.lastLoop.recommendedBolus) { @@ -342,13 +343,13 @@ function init(ctx) { } return valueParts; - } + } - function getForecastPoints ( ) { - var points = [ ]; + function getForecastPoints () { + var points = []; function toPoints (startTime, offset) { - return function toPoint (value, index) { + return function toPoint (value, index) { return { mgdl: value , color: '#ff00ff' @@ -364,12 +365,6 @@ function init(ctx) { if (predicted.values) { points = points.concat(_.map(predicted.values, toPoints(startTime, 0))); } - // if (prop.lastPredBGs.IOB) { - // points = points.concat(_.map(prop.lastPredBGs.IOB, toPoints(moment, 3000))); - // } - // if (prop.lastPredBGs.COB) { - // points = points.concat(_.map(prop.lastPredBGs.COB, toPoints(moment, 7000))); - // } } return points; @@ -386,12 +381,12 @@ function init(ctx) { } else if ('looping' === prop.display.code) { addLastEnacted(); } else { - addRecommendedTempBasal(); + addRecommendedTempBasal(); } - + addRSSI(); - var sorted = _.sortBy(events, function toMill(event) { + var sorted = _.sortBy(events, function toMill (event) { return event.time.valueOf(); }).reverse(); @@ -411,7 +406,7 @@ function init(ctx) { var eventualBGValue = ''; if (prop.lastLoop && prop.lastLoop.predicted) { var predictedBGvalues = prop.lastLoop.predicted.values; - var eventualBG = predictedBGvalues[predictedBGvalues.length-1]; + var eventualBG = predictedBGvalues[predictedBGvalues.length - 1]; if (sbx.settings.units === 'mmol') { eventualBG = sbx.roundBGToDisplayFormat(sbx.scaleMgdl(eventualBG)); } @@ -432,7 +427,7 @@ function init(ctx) { var forecastPoints = getForecastPoints(); if (forecastPoints && forecastPoints.length > 0) { - sbx.pluginBase.addForecastPoints(forecastPoints, {type: 'loop', label: 'Loop Forecasts'}); + sbx.pluginBase.addForecastPoints(forecastPoints, { type: 'loop', label: 'Loop Forecasts' }); } }; @@ -470,7 +465,7 @@ function init(ctx) { } } - function alexaLastLoopHandler(next, slots, sbx) { + function alexaLastLoopHandler (next, slots, sbx) { console.log(JSON.stringify(sbx.properties.loop.lastLoop)); var response = 'The last successful loop was ' + moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)); next('Last loop', response); @@ -523,5 +518,4 @@ function init(ctx) { } - module.exports = init; diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 78c4ad2c..e3deca2c 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -7,7 +7,7 @@ var levels = require('../levels'); // var ALL_STATUS_FIELDS = ['status-symbol', 'status-label', 'iob', 'meal-assist', 'freq', 'rssi']; Unused variable -function init(ctx) { +function init (ctx) { var utils = require('../utils')(ctx); var openaps = { name: 'openaps' @@ -17,7 +17,7 @@ function init(ctx) { var translate = ctx.language.translate; var firstPrefs = true; - openaps.getPrefs = function getPrefs(sbx) { + openaps.getPrefs = function getPrefs (sbx) { function cleanList (value) { return decodeURIComponent(value || '').toLowerCase().split(' '); @@ -27,7 +27,6 @@ function init(ctx) { return _.isEmpty(list) || _.isEmpty(list[0]); } - var fields = cleanList(sbx.extendedSettings.fields); fields = isEmpty(fields) ? ['status-symbol', 'status-label', 'iob', 'meal-assist', 'rssi'] : fields; @@ -51,7 +50,7 @@ function init(ctx) { }; openaps.setProperties = function setProperties (sbx) { - sbx.offerProperty('openaps', function setOpenAPS ( ) { + sbx.offerProperty('openaps', function setOpenAPS () { return openaps.analyzeData(sbx); }); }; @@ -61,10 +60,10 @@ function init(ctx) { var recentMills = sbx.time - times.hours(recentHours).msecs; var recentData = _.chain(sbx.data.devicestatus) - .filter(function (status) { + .filter(function(status) { return ('openaps' in status) && sbx.entryMills(status) <= sbx.time && sbx.entryMills(status) >= recentMills; }) - .map(function (status) { + .map(function(status) { if (status.openaps && _.isArray(status.openaps.iob) && status.openaps.iob.length > 0) { status.openaps.iob = status.openaps.iob[0]; if (status.openaps.iob.time) { @@ -73,7 +72,7 @@ function init(ctx) { } return status; }) - .value( ); + .value(); var prefs = openaps.getPrefs(sbx); var recent = moment(sbx.time).subtract(prefs.warn / 2, 'minutes'); @@ -88,7 +87,7 @@ function init(ctx) { , lastPredBGs: null }; - function getDevice(status) { + function getDevice (status) { var uri = status.device || 'device'; var device = result.seenDevices[uri]; @@ -105,7 +104,7 @@ function init(ctx) { function toMoments (status) { return { - when: moment(status.mills) + when: moment(status.mills) , enacted: status.openaps.enacted && status.openaps.enacted.timestamp && (status.openaps.enacted.recieved || status.openaps.enacted.received) && moment(status.openaps.enacted.timestamp) , notEnacted: status.openaps.enacted && status.openaps.enacted.timestamp && !(status.openaps.enacted.recieved || status.openaps.enacted.received) && moment(status.openaps.enacted.timestamp) , suggested: status.openaps.suggested && status.openaps.suggested.timestamp && moment(status.openaps.suggested.timestamp) @@ -113,7 +112,7 @@ function init(ctx) { }; } - function momentsToLoopStatus (moments, noWarning) { + function momentsToLoopStatus (moments, noWarning) { var status = { symbol: '⚠' @@ -122,8 +121,7 @@ function init(ctx) { }; if (moments.notEnacted && ( - (moments.enacted && moments.notEnacted.isAfter(moments.enacted)) || (!moments.enacted && moments.notEnacted.isAfter(recent))) - ) { + (moments.enacted && moments.notEnacted.isAfter(moments.enacted)) || (!moments.enacted && moments.notEnacted.isAfter(recent)))) { status.symbol = 'x'; status.code = 'notenacted'; status.label = 'Not Enacted'; @@ -160,7 +158,7 @@ function init(ctx) { enacted.moment = moment(enacted.timestamp); result.lastEnacted = enacted; if (enacted.predBGs && (!result.lastPredBGs || enacted.moment.isAfter(result.lastPredBGs.moment))) { - result.lastPredBGs = _.isArray(enacted.predBGs) ? {values: enacted.predBGs} : enacted.predBGs; + result.lastPredBGs = _.isArray(enacted.predBGs) ? { values: enacted.predBGs } : enacted.predBGs; result.lastPredBGs.moment = enacted.moment; } } @@ -175,7 +173,7 @@ function init(ctx) { suggested.moment = moment(suggested.timestamp); result.lastSuggested = suggested; if (suggested.predBGs && (!result.lastPredBGs || suggested.moment.isAfter(result.lastPredBGs.moment))) { - result.lastPredBGs = _.isArray(suggested.predBGs) ? {values: suggested.predBGs} : suggested.predBGs; + result.lastPredBGs = _.isArray(suggested.predBGs) ? { values: suggested.predBGs } : suggested.predBGs; result.lastPredBGs.moment = suggested.moment; } } @@ -203,11 +201,11 @@ function init(ctx) { result.lastEventualBG = result.lastSuggested.eventualBG; } } else if (result.lastEnacted && result.lastEnacted.moment) { - result.lastLoopMoment = result.lastEnacted.moment; - result.lastEventualBG = result.lastEnacted.eventualBG; + result.lastLoopMoment = result.lastEnacted.moment; + result.lastEventualBG = result.lastEnacted.eventualBG; } else if (result.lastSuggested && result.lastSuggested.moment) { - result.lastLoopMoment = result.lastSuggested.moment; - result.lastEventualBG = result.lastSuggested.eventualBG; + result.lastLoopMoment = result.lastSuggested.moment; + result.lastEventualBG = result.lastSuggested.eventualBG; } result.status = momentsToLoopStatus({ @@ -220,43 +218,68 @@ function init(ctx) { }; openaps.getEventTypes = function getEventTypes (sbx) { - - var units = sbx.settings.units; - console.log('units', units); - + + var units = sbx.settings.units; + console.log('units', units); + var reasonconf = []; - + if (units == 'mmol') { - reasonconf.push({ name: translate('Eating Soon'), targetTop: 4.5, targetBottom: 4.5, duration: 60 }); - reasonconf.push({ name: translate('Activity'), targetTop: 8, targetBottom: 6.5, duration: 120 }); + reasonconf.push({ name: translate('Eating Soon'), targetTop: 4.5, targetBottom: 4.5, duration: 60 }); + reasonconf.push({ name: translate('Activity'), targetTop: 8, targetBottom: 6.5, duration: 120 }); } else { - reasonconf.push({ name: translate('Eating Soon'), targetTop: 80, targetBottom: 80, duration: 60 }); - reasonconf.push({ name: translate('Activity'), targetTop: 140, targetBottom: 120, duration: 120 }); + reasonconf.push({ name: translate('Eating Soon'), targetTop: 80, targetBottom: 80, duration: 60 }); + reasonconf.push({ name: translate('Activity'), targetTop: 140, targetBottom: 120, duration: 120 }); } - - reasonconf.push({ name: 'Manual' }); - + + reasonconf.push({ name: 'Manual' }); + return [ { val: 'Temporary Target' , name: 'Temporary Target' - , bg: false, insulin: false, carbs: false, prebolus: false, duration: true, percent: false, absolute: false, profile: false, split: false - , targets: true, reasons: reasonconf + , bg: false + , insulin: false + , carbs: false + , prebolus: false + , duration: true + , percent: false + , absolute: false + , profile: false + , split: false + , targets: true + , reasons: reasonconf } , { val: 'Temporary Target Cancel' , name: 'Temporary Target Cancel' - , bg: false, insulin: false, carbs: false, prebolus: false, duration: false, percent: false, absolute: false, profile: false, split: false - } + , bg: false + , insulin: false + , carbs: false + , prebolus: false + , duration: false + , percent: false + , absolute: false + , profile: false + , split: false + } , { val: 'OpenAPS Offline' , name: 'OpenAPS Offline' - , bg: false, insulin: false, carbs: false, prebolus: false, duration: true, percent: false, absolute: false, profile: false, split: false + , bg: false + , insulin: false + , carbs: false + , prebolus: false + , duration: true + , percent: false + , absolute: false + , profile: false + , split: false } ]; }; - openaps.checkNotifications = function checkNotifications(sbx) { + openaps.checkNotifications = function checkNotifications (sbx) { var prefs = openaps.getPrefs(sbx); if (!prefs.enableAlerts) { return; } @@ -283,8 +306,8 @@ function init(ctx) { } }; - openaps.findOfflineMarker = function findOfflineMarker(sbx) { - return _.findLast(sbx.data.treatments, function match(treatment) { + openaps.findOfflineMarker = function findOfflineMarker (sbx) { + return _.findLast(sbx.data.treatments, function match (treatment) { var eventTime = sbx.entryMills(treatment); var eventEnd = treatment.duration ? eventTime + times.mins(treatment.duration).msecs : eventTime; return eventTime <= sbx.time && treatment.eventType === 'OpenAPS Offline' && eventEnd >= sbx.time; @@ -302,9 +325,9 @@ function init(ctx) { return value ? prefix + value : ''; } - var events = [ ]; + var events = []; - function addSuggestion() { + function addSuggestion () { if (prop.lastSuggested) { var valueParts = [ @@ -337,11 +360,11 @@ function init(ctx) { return valueParts; } - function getForecastPoints ( ) { - var points = [ ]; + function getForecastPoints () { + var points = []; function toPoints (offset, forecastType) { - return function toPoint (value, index) { + return function toPoint (value, index) { return { mgdl: value , color: '#ff00ff' @@ -413,7 +436,7 @@ function init(ctx) { } if (device.mmtune) { - var best = _.maxBy(device.mmtune.scanDetails, function (d) { + var best = _.maxBy(device.mmtune.scanDetails, function(d) { return d[2]; }); @@ -430,7 +453,7 @@ function init(ctx) { }); }); - var sorted = _.sortBy(events, function toMill(event) { + var sorted = _.sortBy(events, function toMill (event) { return event.time.valueOf(); }).reverse(); @@ -455,7 +478,7 @@ function init(ctx) { var forecastPoints = getForecastPoints(); if (forecastPoints && forecastPoints.length > 0) { - sbx.pluginBase.addForecastPoints(forecastPoints, {type: 'openaps', label: 'OpenAPS Forecasts'}); + sbx.pluginBase.addForecastPoints(forecastPoints, { type: 'openaps', label: 'OpenAPS Forecasts' }); } }; @@ -464,8 +487,8 @@ function init(ctx) { var response = translate('alexaOpenAPSForecast', { params: [ sbx.properties.openaps.lastEventualBG - ]} - ); + ] + }); next('Loop Forecast', response); } } diff --git a/lib/plugins/speech.js b/lib/plugins/speech.js index e9032b46..498071c2 100644 --- a/lib/plugins/speech.js +++ b/lib/plugins/speech.js @@ -1,10 +1,6 @@ 'use strict'; -var levels = require('../levels'); -var times = require('../times'); - var lastEntryValue; -var lastTime; var lastMinutes; var lastEntryTime; @@ -78,7 +74,7 @@ function init(ctx) { lastMinutes = timeMinutes; var lastEntryString = translate('Last entry {0} minutes ago'); - var sayIt = lastEntryString.replace('{0}', timeMinutes); + sayIt = lastEntryString.replace('{0}', timeMinutes); speech.say(sayIt); } } diff --git a/lib/profilefunctions.js b/lib/profilefunctions.js index 460c0ba2..c15860ba 100644 --- a/lib/profilefunctions.js +++ b/lib/profilefunctions.js @@ -12,22 +12,22 @@ var prevBasalTreatment = null; function init (profileData) { - var profile = { }; + var profile = {}; var cache = new c.Cache(); profile.loadData = function loadData (profileData) { if (profileData && profileData.length) { - profile.data = profile.convertToProfileStore(profileData); + profile.data = profile.convertToProfileStore(profileData); _.each(profile.data, function eachProfileRecord (record) { _.each(record.store, profile.preprocessProfileOnLoad); record.mills = new Date(record.startDate).getTime(); }); } }; - + profile.convertToProfileStore = function convertToProfileStore (dataArray) { var convertedProfiles = []; - _.each(dataArray, function (profile) { + _.each(dataArray, function(profile) { if (!profile.defaultProfile) { var newObject = {}; newObject.defaultProfile = 'Default'; @@ -51,13 +51,13 @@ function init (profileData) { profile.timeStringToSeconds = function timeStringToSeconds (time) { var split = time.split(':'); - return parseInt(split[0])*3600 + parseInt(split[1])*60; + return parseInt(split[0]) * 3600 + parseInt(split[1]) * 60; }; // preprocess the timestamps to seconds for a couple orders of magnitude faster operation profile.preprocessProfileOnLoad = function preprocessProfileOnLoad (container) { _.each(container, function eachValue (value) { - if( Object.prototype.toString.call(value) === '[object Array]' ) { + if (Object.prototype.toString.call(value) === '[object Array]') { profile.preprocessProfileOnLoad(value); } @@ -67,7 +67,7 @@ function init (profileData) { } }); }; - + profile.getValueByTime = function getValueByTime (time, valueType, spec_profile) { if (!time) { time = Date.now(); } @@ -77,8 +77,8 @@ function init (profileData) { var activeTreatment = profile.activeProfileTreatmentToTime(time); var isCcpProfile = !spec_profile && activeTreatment && activeTreatment.CircadianPercentageProfile; if (isCcpProfile) { - percentage = activeTreatment.percentage; - timeshift = activeTreatment.timeshift; // in hours + percentage = activeTreatment.percentage; + timeshift = activeTreatment.timeshift; // in hours } var offset = timeshift % 24; time = time + offset * times.hours(offset).msecs; @@ -101,7 +101,7 @@ function init (profileData) { // TODO: Better warnings to user for missing configuration var t = profile.getTimezone(spec_profile) ? moment(minuteTime).tz(profile.getTimezone(spec_profile)) : moment(minuteTime); - + // Convert to seconds from midnight var mmtMidnight = t.clone().startOf('day'); var timeAsSecondsFromMidnight = t.clone().diff(mmtMidnight, 'seconds'); @@ -110,7 +110,7 @@ function init (profileData) { returnValue = valueContainer; - if( Object.prototype.toString.call(valueContainer) === '[object Array]' ) { + if (Object.prototype.toString.call(valueContainer) === '[object Array]') { _.each(valueContainer, function eachValue (value) { if (timeAsSecondsFromMidnight >= value.timeAsSeconds) { returnValue = value.value; @@ -118,19 +118,19 @@ function init (profileData) { }); } - if (returnValue) { - returnValue = parseFloat(returnValue); - if (isCcpProfile) { - switch (valueType) { - case "sens": - case "carbratio": - returnValue = returnValue * 100 / percentage; - break; - case "basal": - returnValue = returnValue * percentage / 100; - break; - } + if (returnValue) { + returnValue = parseFloat(returnValue); + if (isCcpProfile) { + switch (valueType) { + case "sens": + case "carbratio": + returnValue = returnValue * 100 / percentage; + break; + case "basal": + returnValue = returnValue * percentage / 100; + break; } + } } cache.put(cacheKey, returnValue, cacheTTL); @@ -186,27 +186,27 @@ function init (profileData) { }; profile.updateTreatments = function updateTreatments (profiletreatments, tempbasaltreatments, combobolustreatments) { - + profile.profiletreatments = profiletreatments || []; profile.tempbasaltreatments = tempbasaltreatments || []; - // dedupe temp basal events + // dedupe temp basal events profile.tempbasaltreatments = _.uniqBy(profile.tempbasaltreatments, 'mills'); - + _.each(profile.tempbasaltreatments, function addDuration (t) { - t.endmills = t.mills + times.mins(t.duration || 0).msecs; + t.endmills = t.mills + times.mins(t.duration || 0).msecs; + }); + + profile.tempbasaltreatments.sort(function compareTreatmentMills (a, b) { + return a.mills - b.mills; }); - - profile.tempbasaltreatments.sort (function compareTreatmentMills (a, b) { - return a.mills - b.mills; - }); profile.combobolustreatments = combobolustreatments || []; profile.profiletreatments_hash = crypto.createHash('sha1').update(JSON.stringify(profile.profiletreatments)).digest('hex'); profile.tempbasaltreatments_hash = crypto.createHash('sha1').update(JSON.stringify(profile.tempbasaltreatments)).digest('hex'); profile.combobolustreatments_hash = crypto.createHash('sha1').update(JSON.stringify(profile.combobolustreatments)).digest('hex'); }; - + profile.activeProfileToTime = function activeProfileToTime (time) { if (profile.hasData()) { var timeprofile = profile.data[0].defaultProfile; @@ -219,7 +219,7 @@ function init (profileData) { } return null; }; - + profile.activeProfileTreatmentToTime = function activeProfileTreatmentToTime (time) { var cacheKey = 'profile' + time + profile.profiletreatments_hash; //var returnValue = profile.timeValueCache[cacheKey]; @@ -231,78 +231,79 @@ function init (profileData) { var treatment = null; if (profile.hasData()) { - profile.profiletreatments.forEach( function eachTreatment (t) { - if (time >= t.mills && t.mills >= profile.data[0].mills) { - var duration = times.mins(t.duration || 0).msecs; - if (duration != 0 && time < t.mills + duration) { - treatment = t; - // if profile switch contains json of profile inject it in to store to be findable by profile name - if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { - if (treatment.profile.indexOf("@@@@@") < 0) - treatment.profile += "@@@@@" + treatment.mills; - var json = JSON.parse(treatment.profileJson); - profile.data[0].store[treatment.profile] = json; - } - } - if (duration == 0) { - treatment = t; - // if profile switch contains json of profile inject it in to store to be findable by profile name - if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { - if (treatment.profile.indexOf("@@@@@") < 0) - treatment.profile += "@@@@@" + treatment.mills; - var json = JSON.parse(treatment.profileJson); - profile.data[0].store[treatment.profile] = json; - } + profile.profiletreatments.forEach(function eachTreatment (t) { + if (time >= t.mills && t.mills >= profile.data[0].mills) { + var duration = times.mins(t.duration || 0).msecs; + if (duration != 0 && time < t.mills + duration) { + treatment = t; + // if profile switch contains json of profile inject it in to store to be findable by profile name + if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { + if (treatment.profile.indexOf("@@@@@") < 0) + treatment.profile += "@@@@@" + treatment.mills; + let json = JSON.parse(treatment.profileJson); + profile.data[0].store[treatment.profile] = json; } } + if (duration == 0) { + treatment = t; + // if profile switch contains json of profile inject it in to store to be findable by profile name + if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { + if (treatment.profile.indexOf("@@@@@") < 0) + treatment.profile += "@@@@@" + treatment.mills; + let json = JSON.parse(treatment.profileJson); + profile.data[0].store[treatment.profile] = json; + } + } + } }); } - + returnValue = treatment; cache.put(cacheKey, returnValue, cacheTTL); return returnValue; }; - profile.profileSwitchName = function profileSwitchName(name) { + profile.profileSwitchName = function profileSwitchName (name) { var index = name.indexOf("@@@@@"); if (index < 0) return name; else return name.substring(0, index); } - + profile.tempBasalTreatment = function tempBasalTreatment (time) { - // Most queries for the data in reporting will match the latest found value, caching that hugely improves performance - if (prevBasalTreatment && time >= prevBasalTreatment.mills && time <= prevBasalTreatment.endmills) { - return prevBasalTreatment; - } - - // Binary search for events for O(log n) performance - var first = 0, last = profile.tempbasaltreatments.length - 1; - - while (first <= last) { - var i = first + Math.floor((last - first) / 2); - var t = profile.tempbasaltreatments[i]; - if (time >= t.mills && time <= t.endmills) { - prevBasalTreatment = t; - return t; - } - if (time < t.mills) { - last = i - 1; - } else { - first = i + 1; - } + // Most queries for the data in reporting will match the latest found value, caching that hugely improves performance + if (prevBasalTreatment && time >= prevBasalTreatment.mills && time <= prevBasalTreatment.endmills) { + return prevBasalTreatment; } - + + // Binary search for events for O(log n) performance + var first = 0 + , last = profile.tempbasaltreatments.length - 1; + + while (first <= last) { + var i = first + Math.floor((last - first) / 2); + var t = profile.tempbasaltreatments[i]; + if (time >= t.mills && time <= t.endmills) { + prevBasalTreatment = t; + return t; + } + if (time < t.mills) { + last = i - 1; + } else { + first = i + 1; + } + } + return null; }; profile.comboBolusTreatment = function comboBolusTreatment (time) { var treatment = null; - profile.combobolustreatments.forEach( function eachTreatment (t) { - var duration = times.mins(t.duration || 0).msecs; - if (time < t.mills + duration && time > t.mills) { - treatment = t; - } + profile.combobolustreatments.forEach(function eachTreatment (t) { + var duration = times.mins(t.duration || 0).msecs; + if (time < t.mills + duration && time > t.mills) { + treatment = t; + } }); return treatment; }; @@ -327,7 +328,7 @@ function init (profileData) { tempbasal = Number(treatment.absolute); } else if (treatment && treatment.percent) { tempbasal = basal * (100 + treatment.percent) / 100; - } + } if (combobolustreatment && combobolustreatment.relative) { combobolusbasal = combobolustreatment.relative; } @@ -348,30 +349,14 @@ function init (profileData) { if (profile.hasData()) { var current = profile.activeProfileToTime(); profiles.push(current); - - for (var key in profile.data[0].store) { - if (profile.data[0].store.hasOwnProperty(key) && key !== current) { - if (key.indexOf('@@@@@') < 0) - profiles.push(key); - } - } + + Object.keys(profile.data[0].store).forEach(key => { + if (key !== current && key.indexOf('@@@@@') < 0) profiles.push(key); + }) } return profiles; }; - // get original store without added profiles fro profileSwitches - profile.getProfileStore = function getProfileStore () { - var newprofiledata = _.clone(profile.data[0]); - for (var key in profile.data[0].store) { - if (profile.data[0].store.hasOwnProperty(key)) { - if (key.indexOf('@@@@@') < 0) - store[key] = profile.data[0].store[key]; - } - } - return store; - }; - - if (profileData) { profile.loadData(profileData); } // init treatments array profile.updateTreatments([], []); @@ -379,4 +364,4 @@ function init (profileData) { return profile; } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/lib/report_plugins/calibrations.js b/lib/report_plugins/calibrations.js index f7088080..958dd06c 100644 --- a/lib/report_plugins/calibrations.js +++ b/lib/report_plugins/calibrations.js @@ -8,30 +8,29 @@ var calibrations = { , pluginType: 'report' }; -function init() { +function init () { return calibrations; } module.exports = init; -calibrations.html = function html(client) { +calibrations.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Calibrations') + '

' - + '
' - + '
' - ; + '

' + translate('Calibrations') + '

' + + '
' + + '
'; return ret; }; -calibrations.report = function report_calibrations(datastorage,sorteddaystoshow) { +calibrations.report = function report_calibrations (datastorage, sorteddaystoshow) { var Nightscout = window.Nightscout; var report_plugins = Nightscout.report_plugins; var padding = { top: 15, right: 15, bottom: 30, left: 70 }; var treatments = []; - sorteddaystoshow.forEach(function (day) { - treatments = treatments.concat(datastorage[day].treatments.filter(function (t) { + sorteddaystoshow.forEach(function(day) { + treatments = treatments.concat(datastorage[day].treatments.filter(function(t) { if (t.eventType === 'Sensor Start') { return true; } @@ -43,59 +42,58 @@ calibrations.report = function report_calibrations(datastorage,sorteddaystoshow) }); var cals = []; - sorteddaystoshow.forEach(function (day) { + sorteddaystoshow.forEach(function(day) { cals = cals.concat(datastorage[day].cal); }); var sgvs = []; - sorteddaystoshow.forEach(function (day) { + sorteddaystoshow.forEach(function(day) { sgvs = sgvs.concat(datastorage[day].sgv); }); - + var mbgs = []; - sorteddaystoshow.forEach(function (day) { + sorteddaystoshow.forEach(function(day) { mbgs = mbgs.concat(datastorage[day].mbg); }); - mbgs.forEach(function (mbg) { calcmbg(mbg); }); - + mbgs.forEach(function(mbg) { calcmbg(mbg); }); var events = treatments.concat(cals).concat(mbgs).sort(function(a, b) { return a.mills - b.mills; }); - - var colors = ['Aqua','Blue','Brown','Chartreuse','Coral','CornflowerBlue','DarkCyan','DarkMagenta','DarkOrange','Fuchsia','Green','Yellow']; + + var colors = ['Aqua', 'Blue', 'Brown', 'Chartreuse', 'Coral', 'CornflowerBlue', 'DarkCyan', 'DarkMagenta', 'DarkOrange', 'Fuchsia', 'Green', 'Yellow']; var colorindex = 0; var html = ''; var lastmbg = null; - for (var i=0; i'; - }; - + } + html += '
'; + html += '' + report_plugins.utils.localeDateTime(new Date(e.mills)) + ''; e.bgcolor = colors[colorindex]; if (e.eventType) { - html += ''+translate(e.eventType)+':
'; + html += '' + translate(e.eventType) + ':
'; } else if (typeof e.device !== 'undefined') { - html += ' '; - html += 'MBG: ' + e.y + ' Raw: '+e.raw+'
'; + html += ' '; + html += 'MBG: ' + e.y + ' Raw: ' + e.raw + '
'; lastmbg = e; e.cals = []; e.checked = false; } else if (typeof e.scale !== 'undefined') { html += 'CAL: ' + ' Scale: ' + e.scale.toFixed(2) + ' Intercept: ' + e.intercept.toFixed(0) + ' Slope: ' + e.slope.toFixed(2) + '
'; - if (lastmbg) { + if (lastmbg) { lastmbg.cals.push(e); } } else { html += JSON.stringify(e); } html += '
'; $('#calibrations-list').html(html); - + // select last 3 mbgs checkLastCheckboxes(3); drawelements(); @@ -103,27 +101,27 @@ calibrations.report = function report_calibrations(datastorage,sorteddaystoshow) $('.calibrations-checkbox').change(checkboxevent); function checkLastCheckboxes (maxcals) { - for (i=events.length-1; i>0; i--) { + for (i = events.length - 1; i > 0; i--) { if (typeof events[i].device !== 'undefined') { events[i].checked = true; - $('#calibrations-'+i).prop('checked',true); - if (--maxcals<1) { + $('#calibrations-' + i).prop('checked', true); + if (--maxcals < 1) { break; } } } } - - function checkboxevent(event) { + + function checkboxevent (event) { var index = $(this).attr('index'); events[index].checked = $(this).is(':checked'); drawelements(); event.preventDefault(); } - function drawelements() { + function drawelements () { drawChart(); - for (var i=0; i5*60*1000) { - console.log('Last SGV too old for MBG. Time diff: '+((mbg.mills-lastsgv.mills)/1000/60).toFixed(1)+' min',mbg); + if (mbg.mills - lastsgv.mills > 5 * 60 * 1000) { + console.log('Last SGV too old for MBG. Time diff: ' + ((mbg.mills - lastsgv.mills) / 1000 / 60).toFixed(1) + ' min', mbg); } else { mbg.raw = lastsgv.filtered || lastsgv.unfiltered; } } else { - console.log('Last entry not found for MBG ',mbg); + console.log('Last entry not found for MBG ', mbg); } } - - function drawmbg(mbg) { + + function drawmbg (mbg) { var color = mbg.bgcolor; if (mbg.raw) { calibration_context.append('circle') @@ -267,11 +265,11 @@ calibrations.report = function report_calibrations(datastorage,sorteddaystoshow) .attr('r', 5); } } - - function findlatest(date,storage) { + + function findlatest (date, storage) { var last = null; var time = date.getTime(); - for (var i=0; i time) { return last; } diff --git a/lib/report_plugins/dailystats.js b/lib/report_plugins/dailystats.js index 4cfd99f8..2f9fa77a 100644 --- a/lib/report_plugins/dailystats.js +++ b/lib/report_plugins/dailystats.js @@ -6,41 +6,39 @@ var dailystats = { , pluginType: 'report' }; -function init() { +function init () { return dailystats; } module.exports = init; -dailystats.html = function html(client) { +dailystats.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Daily stats report') + '

' - + '
' - ; + '

' + translate('Daily stats report') + '

' + + '
'; return ret; }; dailystats.css = - '#dailystats-placeholder .tdborder {' - + ' width:80px;' - + ' border: 1px #ccc solid;' - + ' margin: 0;' - + ' padding: 1px;' - + ' text-align:center;' - + '}' - + '#dailystats-placeholder .inlinepiechart {' - + ' width: 2.0in;' - + ' height: 0.9in;' - + '}' - ; + '#dailystats-placeholder .tdborder {' + + ' width:80px;' + + ' border: 1px #ccc solid;' + + ' margin: 0;' + + ' padding: 1px;' + + ' text-align:center;' + + '}' + + '#dailystats-placeholder .inlinepiechart {' + + ' width: 2.0in;' + + ' height: 0.9in;' + + '}'; -dailystats.report = function report_dailystats(datastorage,sorteddaystoshow,options) { +dailystats.report = function report_dailystats (datastorage, sorteddaystoshow, options) { var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; var report_plugins = Nightscout.report_plugins; - + var ss = require('simple-statistics'); var todo = []; @@ -52,31 +50,31 @@ dailystats.report = function report_dailystats(datastorage,sorteddaystoshow,opti report.append(table); var thead = $('
'+translate('Date')+''+translate('Low')+''+translate('Normal')+''+translate('High')+''+translate('Readings')+''+translate('Min')+''+translate('Max')+''+translate('Average')+''+translate('StDev')+''+translate('25%')+''+translate('Median')+''+translate('75%')+'' + translate('Date') + '' + translate('Low') + '' + translate('Normal') + '' + translate('High') + '' + translate('Readings') + '' + translate('Min') + '' + translate('Max') + '' + translate('Average') + '' + translate('StDev') + '' + translate('25%') + '' + translate('Median') + '' + translate('75%') + '
').appendTo(tr); - $('' + report_plugins.utils.localeDate(day) + ''+translate('No data available')+'' + report_plugins.utils.localeDate(day) + '' + translate('No data available') + '
' + report_plugins.utils.localeDate(day) + '' + Math.round((100 * stats.lows) / daysRecords.length) + '%' + Math.round((100 * stats.normal) / daysRecords.length) + '%' + Math.round((100 * stats.highs) / daysRecords.length) + '%' + daysRecords.length +'' + minForDay +'' + maxForDay +'' + average.toFixed(1) +'' + ss.standard_deviation(bgValues).toFixed(1) + '' + ss.quantile(bgValues, 0.25).toFixed(1) + '' + ss.quantile(bgValues, 0.5).toFixed(1) + '' + ss.quantile(bgValues, 0.75).toFixed(1) + '' + report_plugins.utils.localeDate(day) + '' + Math.round((100 * stats.lows) / daysRecords.length) + '%' + Math.round((100 * stats.normal) / daysRecords.length) + '%' + Math.round((100 * stats.highs) / daysRecords.length) + '%' + daysRecords.length + '' + minForDay + '' + maxForDay + '' + average.toFixed(1) + '' + ss.standard_deviation(bgValues).toFixed(1) + '' + ss.quantile(bgValues, 0.25).toFixed(1) + '' + ss.quantile(bgValues, 0.5).toFixed(1) + '' + ss.quantile(bgValues, 0.75).toFixed(1) + '
')); }); }; -daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) { +daytoday.report = function report_daytoday (datastorage, sorteddaystoshow, options) { var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; var profile = client.sbx.data.profile; var report_plugins = Nightscout.report_plugins; var scaledTreatmentBG = report_plugins.utils.scaledTreatmentBG; - + var TOOLTIP_TRANS_MS = 300; var padding = { top: 15, right: 22, bottom: 30, left: 35 }; @@ -92,28 +91,27 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) var proteinSum = 0; var fatSum = 0; - daytoday.prepareHtml(sorteddaystoshow) ; - sorteddaystoshow.forEach( function eachDay(day) { - drawChart(day,datastorage[day],options); + daytoday.prepareHtml(sorteddaystoshow); + sorteddaystoshow.forEach(function eachDay (day) { + drawChart(day, datastorage[day], options); }); var tddAverage = tddSum / datastorage.alldays; var carbsAverage = carbsSum / datastorage.alldays; var proteinAverage = proteinSum / datastorage.alldays; var fatAverage = fatSum / datastorage.alldays; - if (options.insulindistribution) - $('#daytodaycharts').append('

' + translate('TDD average') + ': ' + tddAverage.toFixed(1) + 'U ' - + translate('Carbs average') + ': ' + carbsAverage.toFixed(0) + 'g' - + translate('Protein average') + ': ' + proteinAverage.toFixed(0) + 'g' - + translate('Fat average') + ': ' + fatAverage.toFixed(0) + 'g' + $('#daytodaycharts').append('

' + translate('TDD average') + ': ' + tddAverage.toFixed(1) + 'U ' + + translate('Carbs average') + ': ' + carbsAverage.toFixed(0) + 'g' + + translate('Protein average') + ': ' + proteinAverage.toFixed(0) + 'g' + + translate('Fat average') + ': ' + fatAverage.toFixed(0) + 'g' ); - function timeTicks(n,i) { - var t12 = [ - '12am', '', '2am', '', '4am', '', '6am', '', '8am', '', '10am', '', - '12pm', '', '2pm', '', '4pm', '', '6pm', '', '8pm', '', '10pm', '', '12am' + function timeTicks (n, i) { + var t12 = [ + '12am', '', '2am', '', '4am', '', '6am', '', '8am', '', '10am', '' + , '12pm', '', '2pm', '', '4pm', '', '6pm', '', '8pm', '', '10pm', '', '12am' ]; if (Nightscout.client.settings.timeFormat === 24) { return ('00' + i).slice(-2); @@ -121,28 +119,28 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) return t12[i]; } } - - function drawChart(day,data,options) { + + function drawChart (day, data, options) { var tickValues , charts , context , xScale2, yScale2 , yInsulinScale, yCarbsScale, yScaleBasals , xAxis2, yAxis2 - , dateFn = function (d) { return new Date(d.date); } + , dateFn = function(d) { return new Date(d.date); } , foodtexts = 0; - tickValues = client.ticks(client, { - scaleY: options.scale === report_plugins.consts.SCALE_LOG ? 'log' : 'linear' - , targetTop: options.targetHigh - , targetBottom: options.targetLow - }); + tickValues = client.ticks(client, { + scaleY: options.scale === report_plugins.consts.SCALE_LOG ? 'log' : 'linear' + , targetTop: options.targetHigh + , targetBottom: options.targetLow + }); - // add defs for combo boluses - var dashWidth = 5; - d3.select('body').append('svg') - .append('defs') - .append('pattern') + // add defs for combo boluses + var dashWidth = 5; + d3.select('body').append('svg') + .append('defs') + .append('pattern') .attr('id', 'hash') .attr('patternUnits', 'userSpaceOnUse') .attr('width', 6) @@ -150,24 +148,24 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .attr('x', 0) .attr('y', 0) .append('g') - .style('fill', 'none') - .style('stroke', '#0099ff') - .style('stroke-width', 2) + .style('fill', 'none') + .style('stroke', '#0099ff') + .style('stroke-width', 2) .append('path').attr('d', 'M0,0 l' + dashWidth + ',' + dashWidth) .append('path').attr('d', 'M' + dashWidth + ',0 l-' + dashWidth + ',' + dashWidth); // create svg and g to contain the chart contents charts = d3.select('#daytodaychart-' + day).html( - ''+ - report_plugins.utils.localeDate(day)+ + '' + + report_plugins.utils.localeDate(day) + '
' - ).append('svg'); + ).append('svg'); charts.append('rect') .attr('width', '100%') .attr('height', '100%') .attr('fill', 'WhiteSmoke'); - + context = charts.append('g'); // define the parts of the axis that aren't dependent on width or height @@ -187,10 +185,10 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .domain([-2 * options.maxInsulinValue, 2 * options.maxInsulinValue]); yCarbsScale = d3.scale.linear() - .domain([0, options.maxCarbsValue*1.25]); + .domain([0, options.maxCarbsValue * 1.25]); yScaleBasals = d3.scale.linear(); - + xAxis2 = d3.svg.axis() .scale(xScale2) .tickFormat(timeTicks) @@ -213,20 +211,20 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) //set the width and height of the SVG element charts.attr('width', options.width) .attr('height', options.height); - + // ranges are based on the width and height available so reset xScale2.range([0, chartWidth]); - yScale2.range([chartHeight,0]); + yScale2.range([chartHeight, 0]); yInsulinScale.range([chartHeight * 2, 0]); - yCarbsScale.range([chartHeight,0]); + yCarbsScale.range([chartHeight, 0]); yScaleBasals.range([yScale2(client.utils.scaleMgdl(72)), chartHeight]); // add target BG rect context.append('rect') - .attr('x', xScale2(dataRange[0])+padding.left) - .attr('y', yScale2(options.targetHigh)+padding.top) - .attr('width', xScale2(dataRange[1]- xScale2(dataRange[0]))) - .attr('height', yScale2(options.targetLow)-yScale2(options.targetHigh)) + .attr('x', xScale2(dataRange[0]) + padding.left) + .attr('y', yScale2(options.targetHigh) + padding.top) + .attr('width', xScale2(dataRange[1] - xScale2(dataRange[0]))) + .attr('height', yScale2(options.targetLow) - yScale2(options.targetHigh)) .style('fill', '#D6FFD6') .attr('stroke', 'grey'); @@ -253,72 +251,68 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .style('fill', 'none') .call(xAxis2); - _.each(tickValues, function (n, li) { + _.each(tickValues, function(n, li) { context.append('line') .attr('class', 'high-line') - .attr('x1', xScale2(dataRange[0])+padding.left) - .attr('y1', yScale2(tickValues[li])+padding.top) - .attr('x2', xScale2(dataRange[1])+padding.left) - .attr('y2', yScale2(tickValues[li])+padding.top) + .attr('x1', xScale2(dataRange[0]) + padding.left) + .attr('y1', yScale2(tickValues[li]) + padding.top) + .attr('x2', xScale2(dataRange[1]) + padding.left) + .attr('y2', yScale2(tickValues[li]) + padding.top) .style('stroke-dasharray', ('1, 5')) .attr('stroke', 'grey'); }); - // bind up the context chart data to an array of circles - var contextCircles = context.selectAll('circle') - .data(data.sgv); - - function prepareContextCircles(sel) { + function prepareContextCircles (sel) { var badData = []; - sel.attr('cx', function (d) { - return xScale2(d.date) + padding.left; + sel.attr('cx', function(d) { + return xScale2(d.date) + padding.left; }) - .attr('cy', function (d) { - if (isNaN(d.sgv)) { - badData.push(d); - return yScale2(client.utils.scaleMgdl(450) + padding.top); - } else { - return yScale2(d.sgv) + padding.top; - } - }) - .attr('fill', function (d) { - if (d.color === 'gray' && !options.raw) { - return 'transparent'; - } - return d.color; - }) - .style('opacity', function () { return 0.5 }) - .attr('stroke-width', function (d) {if (d.type === 'mbg') { return 2; } else if (options.openAps && d.openaps) { return 1; } else { return 0; }}) - .attr('stroke', function () { return 'black'; }) - .attr('r', function(d) { - if (d.type === 'mbg') { - return 4; - } else { - return 2 + (options.width - 800) / 400; - } - }) - .on('mouseover', function (d) { - if (options.openAps && d.openaps) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - var text = 'BG: ' + d.openaps.suggested.bg - + ', ' + d.openaps.suggested.reason - + (d.openaps.suggested.mealAssist ? ' Meal Assist: ' + d.openaps.suggested.mealAssist : ''); - client.tooltip.html(text) - .style('left', (d3.event.pageX) + 'px') - .style('top', (d3.event.pageY + 15) + 'px'); - } - }) - .on('mouseout', hideTooltip); - - if (badData.length > 0) { - console.warn('Bad Data: isNaN(sgv)', badData); + .attr('cy', function(d) { + if (isNaN(d.sgv)) { + badData.push(d); + return yScale2(client.utils.scaleMgdl(450) + padding.top); + } else { + return yScale2(d.sgv) + padding.top; } - return sel; + }) + .attr('fill', function(d) { + if (d.color === 'gray' && !options.raw) { + return 'transparent'; + } + return d.color; + }) + .style('opacity', function() { return 0.5 }) + .attr('stroke-width', function(d) { if (d.type === 'mbg') { return 2; } else if (options.openAps && d.openaps) { return 1; } else { return 0; } }) + .attr('stroke', function() { return 'black'; }) + .attr('r', function(d) { + if (d.type === 'mbg') { + return 4; + } else { + return 2 + (options.width - 800) / 400; + } + }) + .on('mouseover', function(d) { + if (options.openAps && d.openaps) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + var text = 'BG: ' + d.openaps.suggested.bg + + ', ' + d.openaps.suggested.reason + + (d.openaps.suggested.mealAssist ? ' Meal Assist: ' + d.openaps.suggested.mealAssist : ''); + client.tooltip.html(text) + .style('left', (d3.event.pageX) + 'px') + .style('top', (d3.event.pageY + 15) + 'px'); + } + }) + .on('mouseout', hideTooltip); + + if (badData.length > 0) { + console.warn('Bad Data: isNaN(sgv)', badData); } + return sel; + } // PREDICTIONS START // - function preparePredictedData() { + function preparePredictedData () { var treatmentsTimestamps = []; // Only timestamps for (carbs and bolus insulin) treatments will be captured in this array treatmentsTimestamps.push(dataRange[0]); // Create a fake timestamp at midnight so we can show predictions during night @@ -333,14 +327,14 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) if (undefined != treatment.insulin && null != treatment.insulin && treatment.insulin > 0) { if (treatment.timestamp) treatmentsTimestamps.push(treatment.timestamp); - else if (treatment.created_at) - treatmentsTimestamps.push(treatment.created_at); + else if (treatment.created_at) + treatmentsTimestamps.push(treatment.created_at); } } var predictions = []; if (data && data.devicestatus) { - for (var i = data.devicestatus.length - 1; i >= 0; i--) { + for (i = data.devicestatus.length - 1; i >= 0; i--) { if (data.devicestatus[i].loop && data.devicestatus[i].loop.predicted) { predictions.push(data.devicestatus[i].loop.predicted); } else if (data.devicestatus[i].openaps && data.devicestatus[i].openaps.suggested && data.devicestatus[i].openaps.suggested.predBGs) { @@ -363,10 +357,11 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) // Iterate over all treatments, find the predictions for each and add them to the predicted array p for (var treatmentsIndex = 0; treatmentsIndex < treatmentsTimestamps.length; treatmentsIndex++) { var timestamp = treatmentsTimestamps[treatmentsIndex]; + // TODO / BUG: predictedOffset is not set var predictedIndex = findPredicted(predictions, timestamp, predictedOffset); // Find predictions offset before or after timestamp if (predictedIndex != null) { - var entry = predictions[predictedIndex]; // Start entry + entry = predictions[predictedIndex]; // Start entry var d = moment(entry.startDate); var end = moment().endOf('day'); if (options.predictedTruncate) { @@ -399,7 +394,7 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) /* Find the earliest new predicted instance that has a timestamp equal to or larger than timestamp */ /* (so if we have bolused or eaten we want to find the prediction that Loop has estimated just after that) */ /* Returns the index into the predictions array that is the predicted we are looking for */ - function findPredicted(predictions, timestamp, offset) { + function findPredicted (predictions, timestamp, offset) { var ts = moment(timestamp).add(offset, 'minutes'); var predicted = null; if (offset && offset < 0) { // If offset is negative, start searching from first prediction going forward @@ -408,8 +403,8 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) predicted = i; } } - } else { // If offset is positive or zero, start searching from last prediction going backward - for (var i = predictions.length - 1; i > 0; i--) { + } else { // If offset is positive or zero, start searching from last prediction going backward + for (i = predictions.length - 1; i > 0; i--) { if (predictions[i] && predictions[i].startDate && moment(predictions[i].startDate) >= ts) { predicted = i; } @@ -420,7 +415,6 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) // // PREDICTIONS ENDS - // bind up the context chart data to an array of circles var contextData = (options.predicted ? data.sgv.concat(preparePredictedData()) : data.sgv); var contextCircles = context.selectAll('circle').data(contextData); @@ -431,10 +425,11 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) contextCircles.exit() .remove(); - var to = moment(day).add(1, 'days'); - var from = moment(day); - var iobpolyline = '', cobpolyline = ''; - + var to = moment(day).add(1, 'days'); + var from = moment(day); + var iobpolyline = '' + , cobpolyline = ''; + // basals data var linedata = []; var notemplinedata = []; @@ -448,13 +443,13 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) data.netBasalPositive = []; data.netBasalNegative = []; - [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23].forEach(function(hour) { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function(hour) { data.netBasalPositive[hour] = 0; data.netBasalNegative[hour] = 0; }); profile.updateTreatments(datastorage.profileSwitchTreatments, datastorage.tempbasalTreatments, datastorage.combobolusTreatments); - + var bolusInsulin = 0; var baseBasalInsulin = 0; var positiveTemps = 0; @@ -469,9 +464,9 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) console.log("Device COB status available: ", cobStatusAvailable); console.log("Device IOB status available: ", iobStatusAvailable); - for (var dt=moment(from); dt < to; dt.add(5, 'minutes')) { + for (var dt = moment(from); dt < to; dt.add(5, 'minutes')) { if (options.iob && !iobStatusAvailable) { - var iob = client.plugins('iob').calcTotal(datastorage.treatments,datastorage.devicestatus,profile,dt.toDate()).iob; + var iob = client.plugins('iob').calcTotal(datastorage.treatments, datastorage.devicestatus, profile, dt.toDate()).iob; // make the graph discontinuous when data is missing if (iob === undefined) { iobpolyline += ', ' + (xScale2(lastDt) + padding.left) + ',' + (yInsulinScale(0) + padding.top); @@ -480,19 +475,19 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) if (lastIOB === undefined) { iobpolyline += ', ' + (xScale2(dt) + padding.left) + ',' + (yInsulinScale(0) + padding.top); } - iobpolyline += ', '+ (xScale2(dt) + padding.left) + ',' + (yInsulinScale(iob) + padding.top); + iobpolyline += ', ' + (xScale2(dt) + padding.left) + ',' + (yInsulinScale(iob) + padding.top); } lastDt = dt.clone(); lastIOB = iob; } if (options.cob && !cobStatusAvailable) { - var cob = client.plugins('cob').cobTotal(datastorage.treatments,datastorage.devicestatus,profile,dt.toDate()).cob; + var cob = client.plugins('cob').cobTotal(datastorage.treatments, datastorage.devicestatus, profile, dt.toDate()).cob; if (!dt.isSame(from)) { cobpolyline += ', '; } cobpolyline += (xScale2(dt.toDate()) + padding.left) + ',' + (yCarbsScale(cob) + padding.top) + ' '; } - if (options.basal) { + if (options.basal) { var date = dt.format('x'); var hournow = dt.hour(); var basalvalue = profile.getTempBasal(date); @@ -502,26 +497,27 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) if (tempPart > 0) { positiveTemps += tempPart; data.netBasalPositive[hournow] += tempPart; - } if (tempPart < 0) { + } + if (tempPart < 0) { negativeTemps += tempPart; data.netBasalNegative[hournow] += tempPart; } - + if (!_.isEqual(lastbasal, basalvalue)) { - linedata.push( { d: date, b: basalvalue.totalbasal } ); - notemplinedata.push( { d: date, b: basalvalue.basal } ); + linedata.push({ d: date, b: basalvalue.totalbasal }); + notemplinedata.push({ d: date, b: basalvalue.basal }); if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { - tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: basalvalue.totalbasal } ); + tempbasalareadata.push({ d: date, b: basalvalue.tempbasal }); + basalareadata.push({ d: date, b: 0 }); + comboareadata.push({ d: date, b: basalvalue.totalbasal }); } else if (basalvalue.treatment) { - tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: 0 } ); + tempbasalareadata.push({ d: date, b: basalvalue.totalbasal }); + basalareadata.push({ d: date, b: 0 }); + comboareadata.push({ d: date, b: 0 }); } else { - tempbasalareadata.push( { d: date, b: 0 } ); - basalareadata.push( { d: date, b: basalvalue.totalbasal } ); - comboareadata.push( { d: date, b: 0 } ); + tempbasalareadata.push({ d: date, b: 0 }); + basalareadata.push({ d: date, b: basalvalue.totalbasal }); + comboareadata.push({ d: date, b: 0 }); } } lastbasal = basalvalue; @@ -552,8 +548,8 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) // Draw IOB from devicestatuses if available if (iobStatusAvailable) { - var lastdate = 0; - var previousdate = 0; + lastdate = 0; + previousdate = 0; var iobArray = client.plugins('iob').IOBDeviceStatusesInTimeRange(datastorage.devicestatus, from.valueOf(), to.valueOf()); _.each(iobArray, function drawCob (point) { if (previousdate !== 0 && point.mills - previousdate > times.mins(15).msecs) { @@ -577,24 +573,24 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .attr('stroke', 'blue') .attr('opacity', '0.5') .attr('fill-opacity', '0.1') - .attr('points',iobpolyline); - } + .attr('points', iobpolyline); + } if (options.cob) { context.append('polyline') .attr('stroke', 'red') .attr('opacity', '0.5') .attr('fill-opacity', '0.1') - .attr('points',cobpolyline); + .attr('points', cobpolyline); } if (options.basal) { var toTempBasal = profile.getTempBasal(to.format('x')); - linedata.push( { d: to.format('x'), b: toTempBasal.totalbasal } ); - notemplinedata.push( { d: to.format('x'), b: toTempBasal.basal } ); - basalareadata.push( { d: to.format('x'), b: toTempBasal.basal } ); - tempbasalareadata.push( { d: to.format('x'), b: toTempBasal.totalbasal } ); - comboareadata.push( { d: to.format('x'), b: toTempBasal.totalbasal } ); + linedata.push({ d: to.format('x'), b: toTempBasal.totalbasal }); + notemplinedata.push({ d: to.format('x'), b: toTempBasal.basal }); + basalareadata.push({ d: to.format('x'), b: toTempBasal.basal }); + tempbasalareadata.push({ d: to.format('x'), b: toTempBasal.totalbasal }); + comboareadata.push({ d: to.format('x'), b: toTempBasal.totalbasal }); var basalMax = d3.max(linedata, function(d) { return d.b; }); basalMax = Math.max(basalMax, d3.max(basalareadata, function(d) { return d.b; })); @@ -657,7 +653,7 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .attr('stroke-width', 1) .attr('d', area); - datastorage.tempbasalTreatments.forEach(function (t) { + datastorage.tempbasalTreatments.forEach(function(t) { // only if basal and focus interval overlap and there is a chance to fit if (t.mills < to.format('x') && t.mills + times.mins(t.duration).msecs > from.format('x')) { var text = g.append('text') @@ -667,9 +663,9 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) .attr('fill', '#0099ff') .attr('text-anchor', 'middle') .attr('dy', '.35em') - .attr('x', xScale2((Math.max(t.mills, from.format('x')) + Math.min(t.mills + times.mins(t.duration).msecs, to.format('x')))/2) + padding.left) + .attr('x', xScale2((Math.max(t.mills, from.format('x')) + Math.min(t.mills + times.mins(t.duration).msecs, to.format('x'))) / 2) + padding.left) .attr('y', yScaleBasals(0) - 10 + padding.top) -// .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (t.absolute ? Number(t.absolute).toFixed(2) + 'U' : '')); + // .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (t.absolute ? Number(t.absolute).toFixed(2) + 'U' : '')); // better hide if not fit if (text.node().getBBox().width > xScale2(t.mills + times.mins(t.duration).msecs) - xScale2(t.mills)) { text.attr('display', 'none'); @@ -678,8 +674,7 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) }); } - - data.treatments.forEach(function (treatment) { + data.treatments.forEach(function(treatment) { // Calculate bolus stats if (treatment.insulin) { bolusInsulin += treatment.insulin; @@ -698,10 +693,10 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) var drawpointer = false; if (treatment.boluscalc && treatment.boluscalc.foods && treatment.boluscalc.foods.length > 0 && options.food) { var foods = treatment.boluscalc.foods; - for (var fi=0; fi
' + translate('Total carbs') + ':' + data.dailyCarbs + ' g
' + translate('Total protein') + ':' + data.dailyProtein + ' g
' + translate('Total fat') + ':' + data.dailyFat + ' g
'); var thead = $(''); $('').appendTo(thead); @@ -74,50 +73,53 @@ hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, $('').appendTo(thead); thead.appendTo(table); - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function (hour) { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function(hour) { var tr = $(''); var display = new Date(0, 0, 1, hour, 0, 0, 0).toLocaleTimeString().replace(/([\d]+:[\d]{2})(:[\d]{2})(.*)/, '$1$3'); - var avg = Math.floor(pivotedByHour[hour].map(function (r) { - return r.sgv; - }).reduce(function (o, v) { - return o + v; - }, 0) / pivotedByHour[hour].length); + var avg = Math.floor(pivotedByHour[hour].map(function(r) { + return r.sgv; + }).reduce(function(o, v) { + return o + v; + }, 0) / pivotedByHour[hour].length); var d = new Date(times.hours(hour).msecs); - var dev = ss.standard_deviation(pivotedByHour[hour].map(function (r) { + var dev = ss.standard_deviation(pivotedByHour[hour].map(function(r) { return r.sgv; })); stats.push([ - new Date(d), - ss.quantile(pivotedByHour[hour].map(function (r) { + new Date(d) + , ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; - }), 0.25), - ss.quantile(pivotedByHour[hour].map(function (r) { + }), 0.25) + , ss.quantile(pivotedByHour[hour].map(function(r) { return r.sgv; - }), 0.75), - avg - dev, - avg + dev + }), 0.75) + , avg - dev + , avg + dev ]); var tmp; $('').appendTo(tr); $('').appendTo(tr); $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); - $('').appendTo(tr); + $('').appendTo(tr); + // eslint-disable-next-line no-cond-assign + $('').appendTo(tr); + // eslint-disable-next-line no-cond-assign + $('').appendTo(tr); + // eslint-disable-next-line no-cond-assign + $('').appendTo(tr); + $('').appendTo(tr); $('').appendTo(tr); table.append(tr); }); @@ -126,28 +128,27 @@ hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, report.append(table); $.plot( - '#hourlystats-overviewchart', - [{ - data: stats, - candle: true - }], - { + '#hourlystats-overviewchart' + , [{ + data: stats + , candle: true + }], { series: { - candle: true, - lines: false //Somehow it draws lines if you dont disable this. Should investigate and fix this ;) - }, - xaxis: { - mode: 'time', - timeFormat: '%h:00', - min: 0, - max: times.hours(24).msecs - times.secs(1).msecs - }, - yaxis: { - min: 0, - max: options.units === 'mmol' ? 22 : 400, - show: true - }, - grid: { + candle: true + , lines: false //Somehow it draws lines if you dont disable this. Should investigate and fix this ;) + } + , xaxis: { + mode: 'time' + , timeFormat: '%h:00' + , min: 0 + , max: times.hours(24).msecs - times.secs(1).msecs + } + , yaxis: { + min: 0 + , max: options.units === 'mmol' ? 22 : 400 + , show: true + } + , grid: { show: true } } @@ -161,7 +162,7 @@ hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, var days = 0; table = $('
' + translate('Time') + '' + translate('Standard Deviation') + '
' + display + '' + pivotedByHour[hour].length + ' (' + Math.floor(100 * pivotedByHour[hour].length / data.length) + '%)' + avg + '' + Math.min.apply(Math, pivotedByHour[hour].map(function (r) { - return r.sgv; - })) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function (r) { - return r.sgv; - }), 0.25)) ? tmp.toFixed(1) : 0 ) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function (r) { - return r.sgv; - }), 0.5)) ? tmp.toFixed(1) : 0 ) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function (r) { - return r.sgv; - }), 0.75)) ? tmp.toFixed(1) : 0 ) + '' + Math.max.apply(Math, pivotedByHour[hour].map(function (r) { - return r.sgv; - })) + '' + Math.min.apply(Math, pivotedByHour[hour].map(function(r) { + return r.sgv; + })) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { + return r.sgv; + }), 0.25)) ? tmp.toFixed(1) : 0) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { + return r.sgv; + }), 0.5)) ? tmp.toFixed(1) : 0) + '' + ((tmp = ss.quantile(pivotedByHour[hour].map(function(r) { + return r.sgv; + }), 0.75)) ? tmp.toFixed(1) : 0) + '' + Math.max.apply(Math, pivotedByHour[hour].map(function(r) { + return r.sgv; + })) + '' + Math.floor(dev * 10) / 10 + '
'); thead = $(''); - ["", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function (hour) { + ["", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23].forEach(function(hour) { $('').appendTo(thead); totalPositive[hour] = 0; totalNegative[hour] = 0; @@ -171,7 +172,7 @@ hourlystats.report = function report_hourlystats(datastorage, sorteddaystoshow, }); thead.appendTo(table); - sorteddaystoshow.forEach(function (day) { + sorteddaystoshow.forEach(function(day) { if (datastorage[day].netBasalPositive) { days++; var tr = $(''); diff --git a/lib/report_plugins/loopalyzer.js b/lib/report_plugins/loopalyzer.js index 8eb96e68..2d53fa25 100644 --- a/lib/report_plugins/loopalyzer.js +++ b/lib/report_plugins/loopalyzer.js @@ -11,7 +11,7 @@ var loopalyzer = { , pluginType: 'report' }; -function init() { +function init () { return loopalyzer; } @@ -23,80 +23,79 @@ var risingInterpolationGap = 6; // How large a gap in COB/IOB graph is allowed t var fallingInterpolationGap = 24; // And if less than start var interpolationRatio = 1.25; // But do allow rising interpolation if gap larger than interpolationGap and end value is less than 10% larger than start -loopalyzer.html = function html(client) { +loopalyzer.html = function html (client) { var translate = client.translate; var ret = ''; - ret += '

Loopalyzer  

'; - ret += '' + translate('The primary purpose of Loopalyzer is to visualise how the Loop closed loop system performs. It may work with other setups as well, both closed and open loop, and non loop. However depending on which uploader you use, how frequent it is able to capture your data and upload, and how it is able to backfill missing data some graphs may have gaps or even be completely empty. Always ensure the graphs look reasonable. Best is to view one day at a time and scroll through a number of days first to see.'); - ret += '

' + translate('Loopalyzer includes a time shift feature. If you for example have breakfast at 07:00 one day and at 08:00 the day after your average blood glucose curve these two days will most likely look flattened and not show the actual response after a breakfast. Time shift will compute the average time these meals were eaten and then shift all data (carbs, insulin, basal etc.) during both days the corresponding time difference so that both meals align with the average meal start time. '); - ret += '
' + translate('In this example all data from first day is pushed 30 minutes forward in time and all data from second day 30 minutes backward in time so it appears as if you had had breakfast at 07:30 both days. This allows you to see your actual average blood glucose response from a meal.'); - ret += '

' + translate('Time shift highlights the period after the average meal start time in gray, for the duration of the DIA (Duration of Insulin Action). As all data points the entire day are shifted the curves outside the gray area may not be accurate.'); - ret += '

' + translate('Note that time shift is available only when viewing multiple days.'); - ret += '

'; - ret += translate('To see this report, press SHOW while in this view'); - ret += '
'; - ret += ''; - ret += '';/* loopalyzer-button */ - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - ret += '
'; - return ret; + ret += '

Loopalyzer  

'; + ret += '' + translate('The primary purpose of Loopalyzer is to visualise how the Loop closed loop system performs. It may work with other setups as well, both closed and open loop, and non loop. However depending on which uploader you use, how frequent it is able to capture your data and upload, and how it is able to backfill missing data some graphs may have gaps or even be completely empty. Always ensure the graphs look reasonable. Best is to view one day at a time and scroll through a number of days first to see.'); + ret += '

' + translate('Loopalyzer includes a time shift feature. If you for example have breakfast at 07:00 one day and at 08:00 the day after your average blood glucose curve these two days will most likely look flattened and not show the actual response after a breakfast. Time shift will compute the average time these meals were eaten and then shift all data (carbs, insulin, basal etc.) during both days the corresponding time difference so that both meals align with the average meal start time. '); + ret += '
' + translate('In this example all data from first day is pushed 30 minutes forward in time and all data from second day 30 minutes backward in time so it appears as if you had had breakfast at 07:30 both days. This allows you to see your actual average blood glucose response from a meal.'); + ret += '

' + translate('Time shift highlights the period after the average meal start time in gray, for the duration of the DIA (Duration of Insulin Action). As all data points the entire day are shifted the curves outside the gray area may not be accurate.'); + ret += '

' + translate('Note that time shift is available only when viewing multiple days.'); + ret += '

'; + ret += translate('To see this report, press SHOW while in this view'); + ret += '
'; + ret += ''; + ret += ''; /* loopalyzer-button */ + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + ret += '
'; + return ret; }; loopalyzer.css = -'#loopalyzer-charts, #loopalyzer-profiles { padding: 20px; } ' -+ '#loopalyzer-basal, #loopalyzer-bg, #loopalyzer-tempbasal, #loopalyzer-iob, #loopalyzer-cob, #loopalyzer-profiles {' -+ ' width: 100%;' -+ ' height: 100%;' -+ '}' -+ '#loopalyzer-profiles-table table { margin: 0 10px; border-collapse: collapse; border: 0px; }' -+ '#loopalyzer-profiles-table td { vertical-align: top; }' -+ '#loopalyzer-profiles-table td table { margin: 0 10px; border-collapse: collapse; border: 0px; }' -+ '#loopalyzer-profiles-table td caption { text-align: left; font-weight: bold; }' -+ '#loopalyzer-profiles-table td th { background-color: #4CAF50; color: white; }' -+ '#loopalyzer-profiles-table td td { text-align: right; vertical-align: top; padding: 0 1px; }' -+ '#loopalyzer-profiles-table td td td { padding: 1px 8px; }' -; + '#loopalyzer-charts, #loopalyzer-profiles { padding: 20px; } ' + + '#loopalyzer-basal, #loopalyzer-bg, #loopalyzer-tempbasal, #loopalyzer-iob, #loopalyzer-cob, #loopalyzer-profiles {' + + ' width: 100%;' + + ' height: 100%;' + + '}' + + '#loopalyzer-profiles-table table { margin: 0 10px; border-collapse: collapse; border: 0px; }' + + '#loopalyzer-profiles-table td { vertical-align: top; }' + + '#loopalyzer-profiles-table td table { margin: 0 10px; border-collapse: collapse; border: 0px; }' + + '#loopalyzer-profiles-table td caption { text-align: left; font-weight: bold; }' + + '#loopalyzer-profiles-table td th { background-color: #4CAF50; color: white; }' + + '#loopalyzer-profiles-table td td { text-align: right; vertical-align: top; padding: 0 1px; }' + + '#loopalyzer-profiles-table td td td { padding: 1px 8px; }'; -loopalyzer.prepareHtml = function loopalyzerPrepareHtml() { -// $('#loopalyzer-charts').append($('
' + hour + '
')); +loopalyzer.prepareHtml = function loopalyzerPrepareHtml () { + // $('#loopalyzer-charts').append($('
')); }; // loopalyzer.ss = require('simple-statistics'); @@ -111,17 +110,17 @@ loopalyzer.getSGVs = function(datastorage, daysToShow) { // Loop thru the days to show, for each day find the matching SGVs and insert into the bins entry array daysToShow.forEach(function(day) { var entries = []; // Array with all SGVs for this day, we'll fill this and then insert into the bins later - for (var i=0; i<288; i++) entries.push(NaN); // Fill the array with NaNs so we have something in case we don't find an SGV + for (let i = 0; i < 288; i++) entries.push(NaN); // Fill the array with NaNs so we have something in case we don't find an SGV var fromDate = moment(day); var toDate = moment(day); - fromDate.set({'hours':0, 'minutes':0, 'seconds':0, 'milliseconds':0}); - toDate.set({'hours':0, 'minutes':5, 'seconds':0, 'milliseconds':0}); // toDate is 5 mins ahead - for (var i=0; i<288; i++) { + fromDate.set({ 'hours': 0, 'minutes': 0, 'seconds': 0, 'milliseconds': 0 }); + toDate.set({ 'hours': 0, 'minutes': 5, 'seconds': 0, 'milliseconds': 0 }); // toDate is 5 mins ahead + for (let i = 0; i < 288; i++) { var found = false; data.some(function(record) { var recDate = moment(record.displayTime); if (!found && recDate.isAfter(fromDate) && recDate.isBefore(toDate)) { - entries[i]=record.sgv; + entries[i] = record.sgv; found = true; } return found; // Breaks .some loop if found is true @@ -141,10 +140,10 @@ loopalyzer.getBasals = function(datastorage, daysToShow, profile) { var dayStart = moment(day).startOf('day'); var dayEnd = moment(day).endOf('day'); var basals = []; - for (var i=0; i<288; i++) basals.push(NaN); // Clear the basals by filling with NaNs + for (var i = 0; i < 288; i++) basals.push(NaN); // Clear the basals by filling with NaNs var index = 0; - for (var dt=dayStart; dt < dayEnd; dt.add(5, 'minutes')) { + for (var dt = dayStart; dt < dayEnd; dt.add(5, 'minutes')) { var basal = profile.getTempBasal(dt.toDate()); if (basal) basals[index++] = basal.basal; @@ -162,10 +161,10 @@ loopalyzer.getTempBasalDeltas = function(datastorage, daysToShow, profile) { var dayStart = moment(day).startOf('day'); var dayEnd = moment(day).endOf('day'); var temps = []; - for (var i=0; i<288; i++) temps.push(NaN); // Clear the basals by filling with NaNs + for (var i = 0; i < 288; i++) temps.push(NaN); // Clear the basals by filling with NaNs var index = 0; - for (var dt=dayStart; dt < dayEnd; dt.add(5, 'minutes')) { + for (var dt = dayStart; dt < dayEnd; dt.add(5, 'minutes')) { var basal = profile.getTempBasal(dt.toDate()); if (basal) temps[index++] = basal.tempbasal - basal.basal; @@ -188,37 +187,38 @@ loopalyzer.getIOBs = function(datastorage, daysToShow, profile, client, treatmen var iobs = []; if (iobStatusAvailable) { // var dayStartMills = dayStart.milliseconds(); - for (var i=0; i<288; i++) iobs.push(NaN); // Clear the IOBs by filling with NaNs + for (var i = 0; i < 288; i++) iobs.push(NaN); // Clear the IOBs by filling with NaNs var iobArray = client.plugins('iob').IOBDeviceStatusesInTimeRange(datastorage.devicestatus, dayStart.valueOf(), dayEnd.valueOf()); if (laDebug) console.log('getIOBs iobArray', iobArray); - iobArray.forEach(function(entry){ - var index = Math.floor(moment(entry.mills).diff(dayStart,'minutes') / 5); + iobArray.forEach(function(entry) { + var index = Math.floor(moment(entry.mills).diff(dayStart, 'minutes') / 5); iobs[index] = entry.iob; }); - if (daysToShow.length===1) loopalyzer.fillNanWithTreatments(iobs, treatments); + if (daysToShow.length === 1) loopalyzer.fillNanWithTreatments(iobs, treatments); // Loop thru these entries and where no IOB has been found, interpolate between nearby to get a continuous array - var startIndex = 0, stopIndex = 0; + var startIndex = 0 + , stopIndex = 0; while (startIndex < iobs.length && isNaN(iobs[startIndex])) { startIndex++; // Advance start to the first real number } if (startIndex < iobs.length) { - stopIndex = startIndex+1; - while (stopIndex=0 && isNaN(array[start])) {}; - while (stop++ = 0 && isNaN(array[start])) {} + // eslint-disable-next-line no-empty + while (stop++ < array.length && isNaN(array[stop])) {} // var gap = stop - start; // if (isNaN(array[start]) || isNaN(array[stop]) || gap > interpolationGap || (gap < interpolationGap && array[start]= interpolationGap || array[start]==0)) ) { - var interpolate = (isNaN(array[start]) || isNaN(array[stop]) ? true : loopalyzer.canInterpolate(array,start,stop)); + var interpolate = (isNaN(array[start]) || isNaN(array[stop]) ? true : loopalyzer.canInterpolate(array, start, stop)); if (!interpolate) { array[index] = treatment.amount; } @@ -331,12 +336,12 @@ loopalyzer.fillNanWithTreatments = function(array, treatments) { /* Returns true if we can interpolate between this start and end */ loopalyzer.canInterpolate = function(array, start, stop) { var interpolate = false; - if (array[stop] <= array[start]*interpolationRatio) { + if (array[stop] <= array[start] * interpolationRatio) { // Falling - if (stop-start0}).forEach(function(treatment){ + datastorage.treatments.filter(function(treatment) { return treatment.carbs && treatment.carbs > 0 }).forEach(function(treatment) { if (moment(treatment.created_at).isBetween(startDate, endDate)) { - treatments.push({date:treatment.created_at, amount:treatment.carbs}); + treatments.push({ date: treatment.created_at, amount: treatment.carbs }); } }) if (laDebug) console.log('Carb treatments', treatments); @@ -360,11 +365,11 @@ loopalyzer.getCarbTreatments = function(datastorage, daysToShow) { loopalyzer.getInsulinTreatments = function(datastorage, daysToShow) { var treatments = []; // Holds the treatments [date, amount] var startDate = moment(daysToShow[0]); - var endDate = moment(daysToShow[daysToShow.length-1]).add(1, 'days'); + var endDate = moment(daysToShow[daysToShow.length - 1]).add(1, 'days'); - datastorage.treatments.filter(function(treatment){return treatment.insulin && treatment.insulin >0}).forEach(function(treatment){ + datastorage.treatments.filter(function(treatment) { return treatment.insulin && treatment.insulin > 0 }).forEach(function(treatment) { if (moment(treatment.created_at).isBetween(startDate, endDate)) { - treatments.push({date:treatment.created_at, amount:treatment.insulin}); + treatments.push({ date: treatment.created_at, amount: treatment.insulin }); } }) if (laDebug) console.log('Insulin treatments', treatments); @@ -376,12 +381,12 @@ loopalyzer.getInsulinTreatments = function(datastorage, daysToShow) { loopalyzer.getAllTreatmentTimestampsForADay = function(datastorage, day) { var timestamps = []; var dayStart = moment(day).startOf('day'); - var carbTreatments = loopalyzer.getCarbTreatments(datastorage,[day]); - var insulinTreatments = loopalyzer.getInsulinTreatments(datastorage,[day]); - carbTreatments.forEach(function(entry) { timestamps.push(entry.date)}); - insulinTreatments.forEach(function(entry) { timestamps.push(entry.date)}); - timestamps.sort(function(a,b) { return (a= 0; i--) { if (datastorage.devicestatus[i].loop && datastorage.devicestatus[i].loop.predicted) { var predicted = datastorage.devicestatus[i].loop.predicted; - if (moment(predicted.startDate).isSame(dayStart,'day')) + if (moment(predicted.startDate).isSame(dayStart, 'day')) predictions.push(datastorage.devicestatus[i].loop.predicted); } else if (datastorage.devicestatus[i].openaps && datastorage.devicestatus[i].openaps.suggested && datastorage.devicestatus[i].openaps.suggested.predBGs) { var entry = {}; @@ -408,7 +413,7 @@ loopalyzer.getAllPredictionsForADay = function(datastorage, day) { // Remove duplicates before we're done var p = []; predictions.forEach(function(prediction) { - if (p.length === 0 || prediction.startDate !== p[p.length-1].startDate) + if (p.length === 0 || prediction.startDate !== p[p.length - 1].startDate) p.push(prediction); }) return p; @@ -421,13 +426,13 @@ loopalyzer.findPredicted = function(predictions, timestamp, offset) { var ts = moment(timestamp).add(offset, 'minutes'); var predicted = null; if (offset && offset < 0) { // If offset is negative, start searching from first prediction going forward - for (var i = 0; i < predictions.length; i++) { + for (let i = 0; i < predictions.length; i++) { if (predictions[i] && predictions[i].startDate && moment(predictions[i].startDate) <= ts) { predicted = i; } } - } else { // If offset is positive or zero, start searching from last prediction going backward - for (var i = predictions.length - 1; i > 0; i--) { + } else { // If offset is positive or zero, start searching from last prediction going backward + for (let i = predictions.length - 1; i > 0; i--) { if (predictions[i] && predictions[i].startDate && moment(predictions[i].startDate) >= ts) { predicted = i; } @@ -436,7 +441,6 @@ loopalyzer.findPredicted = function(predictions, timestamp, offset) { return predicted; } - loopalyzer.getPredictions = function(datastorage, daysToShow, client) { if (!datastorage.devicestatus) @@ -448,110 +452,112 @@ loopalyzer.getPredictions = function(datastorage, daysToShow, client) { // Fill the bins array with the timestamp, one per 5 minutes var bins = []; var date = moment(); - date.set({'hours':0, 'minutes':0, 'seconds':0, 'milliseconds':0}); - for (var i=0; i<288; i++) { - bins.push([date.toDate(),[]]); + date.set({ 'hours': 0, 'minutes': 0, 'seconds': 0, 'milliseconds': 0 }); + for (var i = 0; i < 288; i++) { + bins.push([date.toDate(), []]); date.add(5, 'minutes'); } daysToShow.forEach(function(day) { - var p = []; // Array with all prediction SGVs for this day, we'll fill this and then insert into the bins later - for (var i=0; i<288; i++) p.push(NaN); - var treatmentTimestamps = loopalyzer.getAllTreatmentTimestampsForADay(datastorage, day); - var predictions = loopalyzer.getAllPredictionsForADay(datastorage, day); + var p = []; // Array with all prediction SGVs for this day, we'll fill this and then insert into the bins later + for (var i = 0; i < 288; i++) p.push(NaN); + var treatmentTimestamps = loopalyzer.getAllTreatmentTimestampsForADay(datastorage, day); + var predictions = loopalyzer.getAllPredictionsForADay(datastorage, day); - if (predictions.length > 0 && treatmentTimestamps.length > 0) { + if (predictions.length > 0 && treatmentTimestamps.length > 0) { - // Iterate over all treatments, find the predictions for each and add them to the entries array p, aligned on timestamp - for (var treatmentsIndex = 0; treatmentsIndex < treatmentTimestamps.length; treatmentsIndex++) { - var timestamp = treatmentTimestamps[treatmentsIndex]; - var predictedIndex = loopalyzer.findPredicted(predictions, timestamp, predictedOffset); // Find predictions offset before or after timestamp + // Iterate over all treatments, find the predictions for each and add them to the entries array p, aligned on timestamp + for (var treatmentsIndex = 0; treatmentsIndex < treatmentTimestamps.length; treatmentsIndex++) { + var timestamp = treatmentTimestamps[treatmentsIndex]; + var predictedIndex = loopalyzer.findPredicted(predictions, timestamp, predictedOffset); // Find predictions offset before or after timestamp - if (predictedIndex != null) { - var entry = predictions[predictedIndex]; // Start entry - var d = moment(entry.startDate); - var end = moment(day).endOf('day'); // Default to stop and end of the day - if (truncatePredictions) { - if (predictedOffset >= 0) { - // But if we are looking forward we want to stop at the next treatment - if (treatmentsIndex < treatmentTimestamps.length - 1) { - end = moment(treatmentTimestamps[treatmentsIndex + 1]); - } - } else { - // And if we are looking backward then we want to stop at "this" treatment - end = moment(treatmentTimestamps[treatmentsIndex]); + if (predictedIndex != null) { + var entry = predictions[predictedIndex]; // Start entry + var d = moment(entry.startDate); + var end = moment(day).endOf('day'); // Default to stop and end of the day + if (truncatePredictions) { + if (predictedOffset >= 0) { + // But if we are looking forward we want to stop at the next treatment + if (treatmentsIndex < treatmentTimestamps.length - 1) { + end = moment(treatmentTimestamps[treatmentsIndex + 1]); } + } else { + // And if we are looking backward then we want to stop at "this" treatment + end = moment(treatmentTimestamps[treatmentsIndex]); } - for (var entryIndex in entry.values) { - if (!d.isAfter(end)) { - var dayStart = moment(d).startOf('day'); - var minutesAfterMidnight = moment(d).diff(dayStart, 'minutes'); - var index = Math.floor(minutesAfterMidnight/5); - p[index] = client.utils.scaleMgdl(entry.values[entryIndex]); - d.add(5, 'minutes'); - } + } + for (var entryIndex in entry.values) { + if (!d.isAfter(end)) { + var dayStart = moment(d).startOf('day'); + var minutesAfterMidnight = moment(d).diff(dayStart, 'minutes'); + var index = Math.floor(minutesAfterMidnight / 5); + p[index] = client.utils.scaleMgdl(entry.values[entryIndex]); + d.add(5, 'minutes'); } } } } - for (var i=0; i<288; i++) { - bins[i][1].push(p[i]); - } - }) - return bins; - } - // - // PREDICTIONS ENDS - + } + for (let i = 0; i < 288; i++) { + bins[i][1].push(p[i]); + } + }) + return bins; +} +// +// PREDICTIONS ENDS // VARIOUS UTILITY FUNCTIONS // /* Create an empty bins array with date stamps for today */ loopalyzer.getEmptyBins = function() { - var bins=[]; + var bins = []; var todayStart = moment().startOf('day'); var todayEnd = moment().endOf('day'); - for (var dt=todayStart; dt < todayEnd; dt.add(5, 'minutes')) { + for (var dt = todayStart; dt < todayEnd; dt.add(5, 'minutes')) { bins.push([dt.toDate(), []]); } - return bins; + return bins; } /* Takes an array of 288 values and adds to the bins */ loopalyzer.addArrayToBins = function(bins, values) { if (bins && bins.length === 288 && values && values.length === 288) { - values.forEach(function(value,index) { + values.forEach(function(value, index) { bins[index][1].push(value); }); - } else + } else console.log('addArrayToBins - array must have 288 items', values); } /* Fill all NaNs in an array by interpolating between adjacent values */ loopalyzer.interpolateArray = function(values, allowNegative) { - var startIndex=0, stopIndex=0, k=0, m=0; + var startIndex = 0 + , stopIndex = 0 + , k = 0 + , m = 0; while (isNaN(values[startIndex])) { startIndex++; // Advance start to the first real number } - stopIndex = startIndex+1; - while (stopIndexmax) max = xBins[i][1]; + if (!isNaN(xBins[i][1]) && xBins[i][1] > max) max = xBins[i][1]; } return max; } /* Compute avg value in bins */ loopalyzer.avg = function(xBins) { - var out=[]; - xBins.forEach(function(entry){ + var out = []; + xBins.forEach(function(entry) { var sum = 0; var count = 0; - entry[1].forEach(function(value){ - if (value && value != NaN) { + entry[1].forEach(function(value) { + if (value && !isNaN(value)) { sum += value; count++; } @@ -599,36 +605,36 @@ loopalyzer.avg = function(xBins) { // Timeshifts a bins array with subarrays for multiple days loopalyzer.timeShiftBins = function(bins, timeShift) { - if (bins && bins.length>0) { - timeShift.forEach(function(minutes, dayIndex){ - if (minutes !==0) { + if (bins && bins.length > 0) { + timeShift.forEach(function(minutes, dayIndex) { + if (minutes !== 0) { var tempBin = []; - bins.forEach(function(){ + bins.forEach(function() { tempBin.push(NaN); // Fill tempBin with NaNs }) - var minutesBy5 = Math.floor(minutes/5); - if (minutesBy5>0) { - var count = 288-minutesBy5; + var minutesBy5 = Math.floor(minutes / 5); + if (minutesBy5 > 0) { + let count = 288 - minutesBy5; // If minutes>0 it means we should shift forward in time // Example: Shift by 15 mins = 3 buckets // bin : 0 1 2 3 4 5 6 7 8 9 10 // tempBin: NaN NaN NaN 0 1 2 3 4 5 6 7 - for (var i=0; i0) { - daysToShow.forEach(function(day, dayIndex){ + if (bin && bin.length > 0) { + daysToShow.forEach(function(day, dayIndex) { var minutesToAdd = timeShift[dayIndex]; var date = moment(day); - bin.forEach(function(entry, entryIndex){ + bin.forEach(function(entry, entryIndex) { var entryDate = moment(entry.date); if (entryDate.isSame(date, 'day')) { entryDate.add(minutesToAdd, 'minutes'); - bin[entryIndex].date=entryDate.toDate(); + bin[entryIndex].date = entryDate.toDate(); } }) }) @@ -654,7 +660,7 @@ loopalyzer.timeShiftSingleBin = function(bin, daysToShow, timeShift) { } /* Returns true if the profile values in a is identical to values in b, false otherwise */ -loopalyzer.isSameProfileValues = function(a,b) { +loopalyzer.isSameProfileValues = function(a, b) { // Because the order of the keys are random when stringifying we do our own custom stringify ourselves var aString = ''; var bString = ''; @@ -697,12 +703,12 @@ loopalyzer.isSameProfileValues = function(a,b) { return (aString == bString); } -loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client) { +loopalyzer.renderProfilesTable = function(datastoreProfiles, daysToShow, client) { // Loop thru the daysToShow and get the timestamp of the first day displayed var beginningOfFirstDay = null; var endOfLastDay = null; - daysToShow.forEach(function (day) { + daysToShow.forEach(function(day) { var dayStart = moment(day).startOf('day'); var dayEnd = moment(day).endOf('day'); if (!beginningOfFirstDay || dayStart < beginningOfFirstDay) @@ -719,16 +725,17 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // these on ascending startDate (create a clone array so we don't modify the Store array). And only save the profiles // that have basal, carbratio, or sens. var profilesArray1 = []; - datastoreProfiles.forEach(function (entry) { + datastoreProfiles.forEach(function(entry) { var newEntry = {}; newEntry.startDate = entry.startDate; - var store=entry.store; + var store = entry.store; if (store) { - for(var key in store){ + for (var key in store) { if (laDebug) console.log('profile ' + key); - if (store.hasOwnProperty(key)){ - var defaultProfile=store[key]; - newEntry.profileName=key; + // eslint-disable-next-line no-prototype-builtins + if (store.hasOwnProperty(key)) { + var defaultProfile = store[key]; + newEntry.profileName = key; if (defaultProfile.basal) newEntry.basal = defaultProfile.basal; if (defaultProfile.carbratio) newEntry.carbratio = defaultProfile.carbratio; if (defaultProfile.sens) newEntry.sens = defaultProfile.sens; @@ -738,9 +745,9 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client } } }) - profilesArray1.sort(function (a, b) { return (a.startDate > b.startDate ? 1 : -1) }); // Ascending + profilesArray1.sort(function(a, b) { return (a.startDate > b.startDate ? 1 : -1) }); // Ascending if (laDebug) { - profilesArray1.forEach(function (entry) { + profilesArray1.forEach(function(entry) { console.log('profilesArray1 - ' + entry.startDate); }) } @@ -750,30 +757,30 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client var profilesArray2 = []; var profileToCompareWith = profilesArray1[0]; profilesArray2.push(profileToCompareWith); // Push the first profile, which should always be included. - profilesArray1.forEach(function (entry) { + profilesArray1.forEach(function(entry) { if (laDebug) { console.log('Comparing ' + JSON.stringify(profileToCompareWith.startDate) + ' to ' + JSON.stringify(entry.startDate)); console.log(profileToCompareWith, entry); } - if (!loopalyzer.isSameProfileValues(profileToCompareWith, entry)) { + if (!loopalyzer.isSameProfileValues(profileToCompareWith, entry)) { profilesArray2.push(entry); profileToCompareWith = entry; - if (laDebug) + if (laDebug) console.log('ADDING IT'); } else { // Do NOT push the entry to profilesArray2, and keep comparing with the same (olders unique) profile - if (laDebug) + if (laDebug) console.log('SKIPPING IT'); } }) if (laDebug) console.log('profilesArray2 has ' + profilesArray2.length + ' profiles'); // Sort the newest Profile first - profilesArray2.sort(function (a, b) { return (a.startDate > b.startDate ? 1 : -1) }); // Ascending + profilesArray2.sort(function(a, b) { return (a.startDate > b.startDate ? 1 : -1) }); // Ascending // Third, find the latest profile with a startDate before beginningOfFirstDay var latestProfile = profilesArray2[0]; // This is the oldest one - profilesArray2.forEach(function (entry) { + profilesArray2.forEach(function(entry) { if (laDebug) console.log(entry.startDate + ' isBefore ' + beginningOfFirstDay + ' = ' + moment(entry.startDate).isBefore(beginningOfFirstDay)); if (moment(entry.startDate).isBefore(beginningOfFirstDay)) @@ -785,7 +792,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // the other profiles with a startDate between beginningOfFirstDay and endOfLastDay var profiles = []; profiles.push(latestProfile); // Add the latest one - profilesArray2.forEach(function (entry) { + profilesArray2.forEach(function(entry) { if (laDebug) console.log(entry.startDate + ' isAfter ' + beginningOfFirstDay + ' = ' + moment(entry.startDate).isAfter(beginningOfFirstDay)); if (moment(entry.startDate).isAfter(beginningOfFirstDay)) @@ -794,7 +801,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // Now we have an array of all the profiles that are relevant for the days we are displaying. if (laDebug) { - profiles.forEach(function (entry) { + profiles.forEach(function(entry) { console.log('profiles - ' + entry.startDate); }) } @@ -803,7 +810,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client var translate = client.translate; var tableHtml = ''; - profiles.forEach(function (theProfile, index) { + profiles.forEach(function(theProfile, index) { if (index < 3) { tableHtml += '
'; @@ -814,7 +821,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // Add Basal as a table in the first td tableHtml += '
'; if (theProfile.basal) { - theProfile.basal.forEach(function (entry) { + theProfile.basal.forEach(function(entry) { tableHtml += '' }); } @@ -823,7 +830,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // Add Carb Ratio as a table in the second td tableHtml += '
' + entry.time + '' + parseFloat(entry.value).toFixed(3) + '
'; if (theProfile.carbratio) { - theProfile.carbratio.forEach(function (entry) { + theProfile.carbratio.forEach(function(entry) { tableHtml += '' }); } @@ -832,7 +839,7 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // Add Sensitivity as a table in the third td tableHtml += ''; - } else - if (index == 3) { + } else + if (index == 3) { // Add ellipsis if too many profiles to display, but only one ellipsis even if there are more profiles tableHtml += ''; } @@ -857,16 +864,16 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client }; // Main method -loopalyzer.report = function(datastorage,sorteddaystoshow,options) { +loopalyzer.report = function(datastorage, sorteddaystoshow, options) { if (laDebug) console.log('Loopalyzer ' + laVersion); // Copy the sorteddaystoshow into new array (clone) and re-sort ascending (so we don't mess with original array) var daysToShow = []; - sorteddaystoshow.forEach(function(day){daysToShow.push(day)}); - daysToShow.sort(function(a,b) { return (a1) dateInfo += ' - ' + moment(daysToShow[daysToShow.length-1]).format('ddd MMM D'); // .split(',')[0]; + if (daysToShow.length > 1) dateInfo += ' - ' + moment(daysToShow[daysToShow.length - 1]).format('ddd MMM D'); // .split(',')[0]; $("#loopalyzer-dateinfo").html(dateInfo); loopalyzer.prepareHtml(); $("#loopalyzer-buttons").show(); - if (daysToShow.length==1) { + if (daysToShow.length == 1) { // Disable and gray out timeShift if only a single day $("#rp_loopalyzertimeshift").prop('checked', false); $("#rp_loopalyzertimeshift").attr("disabled", true); @@ -925,23 +931,23 @@ loopalyzer.generateReport = function(datastorage,daysToShow,options) { if ($("#rp_loopalyzerprofiles").is(":checked") && (datastorage.profiles && datastorage.profiles.length > 0)) { $("#loopalyzer-profiles-table").show(); loopalyzer.renderProfilesTable(datastorage.profiles, daysToShow, client); - } else + } else $("#loopalyzer-profiles-table").hide(); // Pull all necessary treatment information profile.updateTreatments(datastorage.profileSwitchTreatments, datastorage.tempbasalTreatments, datastorage.combobolusTreatments); - var carbTreatments = loopalyzer.getCarbTreatments(datastorage,daysToShow); - var insulinTreatments = loopalyzer.getInsulinTreatments(datastorage,daysToShow); - var sgvBin = loopalyzer.getSGVs(datastorage,daysToShow); - var basalsBin = loopalyzer.getBasals(datastorage,daysToShow,profile); - var tempBasalsBin = loopalyzer.getTempBasalDeltas(datastorage,daysToShow,profile); - var iobBin = loopalyzer.getIOBs(datastorage,daysToShow, profile, client, insulinTreatments); - var cobBin = loopalyzer.getCOBs(datastorage,daysToShow, profile, client, carbTreatments); + var carbTreatments = loopalyzer.getCarbTreatments(datastorage, daysToShow); + var insulinTreatments = loopalyzer.getInsulinTreatments(datastorage, daysToShow); + var sgvBin = loopalyzer.getSGVs(datastorage, daysToShow); + var basalsBin = loopalyzer.getBasals(datastorage, daysToShow, profile); + var tempBasalsBin = loopalyzer.getTempBasalDeltas(datastorage, daysToShow, profile); + var iobBin = loopalyzer.getIOBs(datastorage, daysToShow, profile, client, insulinTreatments); + var cobBin = loopalyzer.getCOBs(datastorage, daysToShow, profile, client, carbTreatments); var predictionsBin = []; if ($("#rp_loopalyzerpredictions").is(":checked")) { - predictionsBin = loopalyzer.getPredictions(datastorage,daysToShow,client); + predictionsBin = loopalyzer.getPredictions(datastorage, daysToShow, client); } // Prepare an array with the minutes to timeShift each day (0 as default since timeShift is off by default) @@ -950,76 +956,80 @@ loopalyzer.generateReport = function(datastorage,daysToShow,options) { var timeShiftStartTime = null; // If timeShifting this is the average time the meals were eaten var timeShiftStopTime = null; // and this is the start + DIA according to profile var doTimeShift = false; - daysToShow.forEach(function(){ timeShifts.push(0); firstCarbs.push(NaN) }); + daysToShow.forEach(function() { timeShifts.push(0); + firstCarbs.push(NaN) }); // Check to see if we are doing timeShift or not - if ($("#rp_loopalyzertimeshift").is(":checked") && daysToShow.length>1) { + if ($("#rp_loopalyzertimeshift").is(":checked") && daysToShow.length > 1) { var mealMinCarbs = $("#rp_loopalyzermincarbs").val(); var t1 = $("#rp_loopalyzert1").val(); var t2 = $("#rp_loopalyzert2").val(); - if (t2>t1) { + if (t2 > t1) { var h1 = t1.split(':')[0]; var m1 = t1.split(':')[1]; var h2 = t2.split(':')[0]; var m2 = t2.split(':')[1]; - + var timeShiftBegin = moment(); - timeShiftBegin.set({'hours':h1, 'minutes':m1, 'seconds':0}); - + timeShiftBegin.set({ 'hours': h1, 'minutes': m1, 'seconds': 0 }); + var timeShiftEnd = moment(); - timeShiftEnd.set({'hours':h2, 'minutes':m2, 'seconds':0}); - + timeShiftEnd.set({ 'hours': h2, 'minutes': m2, 'seconds': 0 }); + //Loop through the carb treatments and find the first meal each day - daysToShow.forEach(function(day, dayIndex){ + daysToShow.forEach(function(day, dayIndex) { var timeShiftBegin = moment(day); var timeShiftEnd = moment(day); - timeShiftBegin.set({'hours':h1, 'minutes':m1, 'seconds':0}); - timeShiftEnd.set({'hours':h2, 'minutes':m2, 'seconds':0}); - + timeShiftBegin.set({ 'hours': h1, 'minutes': m1, 'seconds': 0 }); + timeShiftEnd.set({ 'hours': h2, 'minutes': m2, 'seconds': 0 }); + var found = false; - carbTreatments.forEach(function(entry){ + carbTreatments.forEach(function(entry) { if (!found && entry.amount >= mealMinCarbs) { var date = moment(entry.date); - if ( (date.isSame(timeShiftBegin,'minute') || date.isAfter(timeShiftBegin,'minute')) && - (date.isSame(timeShiftEnd,'minute') || date.isBefore(timeShiftEnd,'minute')) ) { - var startOfDay = moment(entry.date); - startOfDay.set({'hours':0, 'minutes':0, 'seconds':0}); - var minutesAfterMidnight = date.diff(startOfDay, 'minutes'); - firstCarbs[dayIndex]=minutesAfterMidnight; - found = true; - doTimeShift = true; + if ((date.isSame(timeShiftBegin, 'minute') || date.isAfter(timeShiftBegin, 'minute')) && + (date.isSame(timeShiftEnd, 'minute') || date.isBefore(timeShiftEnd, 'minute'))) { + var startOfDay = moment(entry.date); + startOfDay.set({ 'hours': 0, 'minutes': 0, 'seconds': 0 }); + var minutesAfterMidnight = date.diff(startOfDay, 'minutes'); + firstCarbs[dayIndex] = minutesAfterMidnight; + found = true; + doTimeShift = true; } } }) }) - + // Calculate the average starting time, in minutes after midnight - var averageMinutesAfterMidnight = 0, sum = 0, count = 0; - firstCarbs.forEach(function(minutesAfterMidnight){ + var sum = 0 + , count = 0; + + firstCarbs.forEach(function(minutesAfterMidnight) { if (minutesAfterMidnight) { // Avoid NaN sum += minutesAfterMidnight; count++; } }); + var averageMinutesAfterMidnight = Math.round(sum / count); - + var dia = profile.getDIA(); if (!dia || dia <= 0) - dia=6; // Default to 6h if DIA not set in profile + dia = 6; // Default to 6h if DIA not set in profile timeShiftStartTime = moment(todayJSON); timeShiftStartTime.minutes(averageMinutesAfterMidnight); timeShiftStopTime = moment(todayJSON); - if (averageMinutesAfterMidnight + dia*60 < 24*60) - timeShiftStopTime.minutes(averageMinutesAfterMidnight + dia*60); // If not beyond midnight, stop at end of DIA + if (averageMinutesAfterMidnight + dia * 60 < 24 * 60) + timeShiftStopTime.minutes(averageMinutesAfterMidnight + dia * 60); // If not beyond midnight, stop at end of DIA else - timeShiftStopTime.minutes(24*60-1); // If beyond midnight, stop at midnight - + timeShiftStopTime.minutes(24 * 60 - 1); // If beyond midnight, stop at midnight + // Compute the timeShift (+ / -) that we should add to each entry (sgv, iob, carbs, etc) for each day - firstCarbs.forEach(function(minutesAfterMidnight,index){ + firstCarbs.forEach(function(minutesAfterMidnight, index) { if (minutesAfterMidnight) { // Avoid NaN var delta = Math.round(averageMinutesAfterMidnight - minutesAfterMidnight); - timeShifts[index]=delta; + timeShifts[index] = delta; } }); @@ -1050,7 +1060,7 @@ loopalyzer.generateReport = function(datastorage,daysToShow,options) { var low = options.targetLow; // Set up the charts basics - function tickFormatter(val,axis) { + function tickFormatter (val, axis) { if (val <= axis.min) { return ''; } if (val >= axis.max) { return ''; } return val + ''; @@ -1068,200 +1078,195 @@ loopalyzer.generateReport = function(datastorage,daysToShow,options) { var borderWidth = 1; var labelWidth = 25; var xaxisCfg = { - mode: 'time', - timezone: 'browser', - timeformat: '%H:%M', - tickColor: tickColor, - tickSize: [1, "hour"], - font: { size: 0 } + mode: 'time' + , timezone: 'browser' + , timeformat: '%H:%M' + , tickColor: tickColor + , tickSize: [1, "hour"] + , font: { size: 0 } }; var hiddenAxis = { - position: "right", - show: true, - labelWidth: 10, - tickColor: "#FFFFFF", - font: { size: 0} + position: "right" + , show: true + , labelWidth: 10 + , tickColor: "#FFFFFF" + , font: { size: 0 } } // For drawing the carbs and insulin treatments var markings = []; var markingColor = "#000000"; - // Chart 1: Basal markings = []; if (doTimeShift) - markings.push( { xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate()}, color: timeShiftBackgroundColor } ); + markings.push({ xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate() }, color: timeShiftBackgroundColor }); var chartBasalData = [{ - data: basalsAvg, - label: translate('Basal profile'), - id: 'basals', - color: basalColor, - points: { show: false }, - bars: { show: true, fill: true, barWidth: barWidth }, - yaxis: 1 + data: basalsAvg + , label: translate('Basal profile') + , id: 'basals' + , color: basalColor + , points: { show: false } + , bars: { show: true, fill: true, barWidth: barWidth } + , yaxis: 1 }]; var chartBasalOptions = { - xaxis: xaxisCfg, - yaxes: [{ - tickColor: tickColor, - labelWidth: labelWidth, - tickFormatter: function(val,axis) { return tickFormatter(val,axis); } - }, - hiddenAxis], - grid: { - borderWidth: borderWidth, - markings: markings + xaxis: xaxisCfg + , yaxes: [{ + tickColor: tickColor + , labelWidth: labelWidth + , tickFormatter: function(val, axis) { return tickFormatter(val, axis); } + } + , hiddenAxis] + , grid: { + borderWidth: borderWidth + , markings: markings } }; - $.plot( '#loopalyzer-basal', chartBasalData, chartBasalOptions ); - + $.plot('#loopalyzer-basal', chartBasalData, chartBasalOptions); // Chart 2: Blood glucose markings = []; if (doTimeShift) - markings.push( { xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate()}, color: timeShiftBackgroundColor } ); + markings.push({ xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate() }, color: timeShiftBackgroundColor }); markings.push({ yaxis: { from: low, to: high }, color: glucoseRangeColor }); var chartBGData = [{ - label: translate('Blood glucose'), - data: sgvAvg, - id: 'glucose', - color: glucoseColor, - points: { show: false }, - lines: { show: true } + label: translate('Blood glucose') + , data: sgvAvg + , id: 'glucose' + , color: glucoseColor + , points: { show: false } + , lines: { show: true } }]; - if (predictionsAvg && predictionsAvg.length>0) { + if (predictionsAvg && predictionsAvg.length > 0) { chartBGData.push({ - label: translate('Predictions'), - data: predictionsAvg, - id: 'predictions', - color: predictionsColor, - points: { show: true, fill: true, radius: 0.75, fillColor: predictionsColor }, - lines: { show: false } + label: translate('Predictions') + , data: predictionsAvg + , id: 'predictions' + , color: predictionsColor + , points: { show: true, fill: true, radius: 0.75, fillColor: predictionsColor } + , lines: { show: false } }); } var chartBGOptions = { - xaxis: xaxisCfg, - yaxes: [{ - min: 0, - max: options.units === 'mmol' ? 20 : 400, - tickColor: tickColor, - labelWidth: labelWidth, - tickFormatter: function(val,axis) { return tickFormatter(val,axis); } - }, - hiddenAxis], - grid: { - borderWidth: borderWidth, - markings: markings + xaxis: xaxisCfg + , yaxes: [{ + min: 0 + , max: options.units === 'mmol' ? 20 : 400 + , tickColor: tickColor + , labelWidth: labelWidth + , tickFormatter: function(val, axis) { return tickFormatter(val, axis); } + } + , hiddenAxis] + , grid: { + borderWidth: borderWidth + , markings: markings } }; - $.plot( '#loopalyzer-bg', chartBGData, chartBGOptions ); - + $.plot('#loopalyzer-bg', chartBGData, chartBGOptions); // Chart 3: Delta temp basals markings = []; if (doTimeShift) - markings.push( { xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate()}, color: timeShiftBackgroundColor } ); - markings.push( { yaxis: { from: 0, to: 0 }, color: insulinColor, lineWidth: 2 }); + markings.push({ xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate() }, color: timeShiftBackgroundColor }); + markings.push({ yaxis: { from: 0, to: 0 }, color: insulinColor, lineWidth: 2 }); var chartTempBasalData = [{ - data: tempBasalsAvg, - label: translate('Temp basal delta'), - id: 'tempBasals', - color: insulinColor, - points: { show: false }, - bars: { show: true, barWidth: barWidth } + data: tempBasalsAvg + , label: translate('Temp basal delta') + , id: 'tempBasals' + , color: insulinColor + , points: { show: false } + , bars: { show: true, barWidth: barWidth } }]; var chartTempBasalOptions = { - xaxis: xaxisCfg, - yaxes: [{ - tickColor: tickColor, - labelWidth: labelWidth, - tickFormatter: function(val,axis) { return tickFormatter(val,axis); } - }, - hiddenAxis], - grid: { - borderWidth: borderWidth, - markings: markings + xaxis: xaxisCfg + , yaxes: [{ + tickColor: tickColor + , labelWidth: labelWidth + , tickFormatter: function(val, axis) { return tickFormatter(val, axis); } + } + , hiddenAxis] + , grid: { + borderWidth: borderWidth + , markings: markings } }; - $.plot( '#loopalyzer-tempbasal', chartTempBasalData, chartTempBasalOptions ); - + $.plot('#loopalyzer-tempbasal', chartTempBasalData, chartTempBasalOptions); // Chart 4: IOB markings = []; if (doTimeShift) - markings.push( { xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate()}, color: timeShiftBackgroundColor } ); - insulinTreatments.forEach(function(treatment){ + markings.push({ xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate() }, color: timeShiftBackgroundColor }); + insulinTreatments.forEach(function(treatment) { var startDate = moment(treatment.date); var endDate = moment(treatment.date); startDate.set(todayJSON); endDate.set(todayJSON); endDate.add(5, 'minutes'); - markings.push( { xaxis: { from: startDate.toDate(), to: endDate.toDate()}, yaxis: { from: 0, to: treatment.amount }, color: markingColor } ); + markings.push({ xaxis: { from: startDate.toDate(), to: endDate.toDate() }, yaxis: { from: 0, to: treatment.amount }, color: markingColor }); }) var chartIOBData = [{ - data: iobAvg, - label: translate('IOB'), - id: 'iobs', - color: insulinColor, - points: { show: false }, - bars: { show: true, fill: true, barWidth: barWidth } + data: iobAvg + , label: translate('IOB') + , id: 'iobs' + , color: insulinColor + , points: { show: false } + , bars: { show: true, fill: true, barWidth: barWidth } }]; var chartIOBOptions = { - xaxis: xaxisCfg, - yaxes: [{ - tickColor: tickColor, - labelWidth: labelWidth, - tickFormatter: function(val,axis) { return tickFormatter(val,axis); } - }, - hiddenAxis], - grid: { - borderWidth: borderWidth, - markings: markings + xaxis: xaxisCfg + , yaxes: [{ + tickColor: tickColor + , labelWidth: labelWidth + , tickFormatter: function(val, axis) { return tickFormatter(val, axis); } + } + , hiddenAxis] + , grid: { + borderWidth: borderWidth + , markings: markings } }; - $.plot( '#loopalyzer-iob', chartIOBData, chartIOBOptions ); - + $.plot('#loopalyzer-iob', chartIOBData, chartIOBOptions); // Chart 5: COB markings = []; if (doTimeShift) - markings.push( { xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate()}, color: timeShiftBackgroundColor } ); - carbTreatments.forEach(function(treatment){ + markings.push({ xaxis: { from: timeShiftStartTime.toDate(), to: timeShiftStopTime.toDate() }, color: timeShiftBackgroundColor }); + carbTreatments.forEach(function(treatment) { var startDate = moment(treatment.date); var endDate = moment(treatment.date); startDate.set(todayJSON); endDate.set(todayJSON); endDate.add(5, 'minutes'); - markings.push( { xaxis: { from: startDate.toDate(), to: endDate.toDate()}, yaxis: { from: 0, to: treatment.amount }, color: markingColor } ); + markings.push({ xaxis: { from: startDate.toDate(), to: endDate.toDate() }, yaxis: { from: 0, to: treatment.amount }, color: markingColor }); }) delete xaxisCfg.font; // Remove the font config so HH:MM is shown on the last chart var chartCOBData = [{ - data: cobAvg, - label: translate('COB'), - id: 'cobs', - color: carbColor, - points: { show: false }, - bars: { show: true, fil: true, barWidth: barWidth } + data: cobAvg + , label: translate('COB') + , id: 'cobs' + , color: carbColor + , points: { show: false } + , bars: { show: true, fil: true, barWidth: barWidth } }]; var chartCOBOptions = { - xaxis: xaxisCfg, - yaxes: [{ - tickColor: tickColor, - labelWidth: labelWidth, - tickFormatter: function(val,axis) { return tickFormatter(val,axis); } - }, - hiddenAxis], - grid: { - borderWidth: borderWidth, - markings: markings + xaxis: xaxisCfg + , yaxes: [{ + tickColor: tickColor + , labelWidth: labelWidth + , tickFormatter: function(val, axis) { return tickFormatter(val, axis); } + } + , hiddenAxis] + , grid: { + borderWidth: borderWidth + , markings: markings } }; - $.plot( '#loopalyzer-cob', chartCOBData, chartCOBOptions ); + $.plot('#loopalyzer-cob', chartCOBData, chartCOBOptions); }; diff --git a/lib/report_plugins/profiles.js b/lib/report_plugins/profiles.js index c31b8b2f..58036789 100644 --- a/lib/report_plugins/profiles.js +++ b/lib/report_plugins/profiles.js @@ -6,33 +6,32 @@ var profiles = { , pluginType: 'report' }; -function init() { +function init () { return profiles; } module.exports = init; -profiles.html = function html(client) { +profiles.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Profiles') + '

' - + '
' + translate('Database records') + ' ' - + '
' - + '
' - + '
' - + '
' - ; + '

' + translate('Profiles') + '

' + + '
' + translate('Database records') + ' ' + + '
' + + '
' + + '
' + + '
'; return ret; }; profiles.css = - '#profiles-chart {' - + ' width: 100%;' - + ' height: 100%;' - + '}' - ; + '#profiles-chart {' + + ' width: 100%;' + + ' height: 100%;' + + '}'; -profiles.report = function report_profiles(datastorage, sorteddaystoshow, options) { +// eslint-disable-next-line no-unused-vars +profiles.report = function report_profiles (datastorage, sorteddaystoshow, options) { var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; @@ -41,10 +40,10 @@ profiles.report = function report_profiles(datastorage, sorteddaystoshow, option var databaseRecords = $('#profiles-databaserecords'); databaseRecords.empty(); - for (var r = 0; r < profileRecords.length; r++ ) { + for (var r = 0; r < profileRecords.length; r++) { databaseRecords.append(''); } - databaseRecords.unbind().bind('change',recordChange); + databaseRecords.unbind().bind('change', recordChange); recordChange(); @@ -58,11 +57,10 @@ profiles.report = function report_profiles(datastorage, sorteddaystoshow, option var tr = $('
'); $('#profiles-default').val(currentrecord.defaultProfile); - for (var key in currentrecord.store) { - if (currentrecord.store.hasOwnProperty(key)) { - tr.append(displayRecord(currentrecord.store[key], key)) - } - } + + Object.keys(currentrecord.store).forEach(key => { + tr.append(displayRecord(currentrecord.store[key], key)); + }); table.append(tr); @@ -73,7 +71,7 @@ profiles.report = function report_profiles(datastorage, sorteddaystoshow, option } } - function displayRecord(record, name) { + function displayRecord (record, name) { var td = $('
' + entry.time + '' + parseFloat(entry.value).toFixed(1) + '
'; if (theProfile.sens) { - theProfile.sens.forEach(function (entry) { + theProfile.sens.forEach(function(entry) { tableHtml += '' }); } @@ -841,8 +848,8 @@ loopalyzer.renderProfilesTable = function (datastoreProfiles, daysToShow, client // Close theProfile table tableHtml += '
' + entry.time + '' + parseFloat(entry.value).toFixed(1) + '
.....
'); var table = $(''); @@ -91,7 +89,7 @@ profiles.report = function report_profiles(datastorage, sorteddaystoshow, option return td; } - function displayRanges(array, array2) { + function displayRanges (array, array2) { var text = ''; for (var i = 0; i < array.length; i++) { text += array[i].time + ' : ' + array[i].value + (array2 ? ' - ' + array2[i].value : '') + '
'; diff --git a/lib/report_plugins/success.js b/lib/report_plugins/success.js index d4ee4b91..a08ef8d0 100644 --- a/lib/report_plugins/success.js +++ b/lib/report_plugins/success.js @@ -8,66 +8,60 @@ var success = { , pluginType: 'report' }; -function init() { +function init () { return success; } module.exports = init; -success.html = function html(client) { +success.html = function html (client) { var translate = client.translate; var ret = - '

' + translate('Weekly Success') + '

' - + '
' - ; + '

' + translate('Weekly Success') + '

' + + '
'; return ret; }; -success.css = - '#success-placeholder td {'+ - ' border: 1px #ccc solid;'+ - ' margin: 0;'+ - ' padding: 1px;'+ - ' text-align:center;'+ - '}'+ - '#success-placeholder .bad {'+ - ' background-color: #fcc;'+ - '}'+ +success.css = + `#success-placeholder td { + border: 1px #ccc solid; + margin: 0; + padding: 1px; + text-align:center; + } + #success-placeholder .bad { + background-color: #fcc; + } + #success-placeholder .good { + background-color: #cfc; + } + #success-placeholder th:first-child { + width: 30%; + } + #success-placeholder th { + width: 10%; + } + #success-placeholder table { + width: 100%; + }`; - '#success-placeholder .good {'+ - ' background-color: #cfc;'+ - '}'+ - - '#success-placeholder th:first-child {'+ - ' width: 30%;'+ - '}'+ - '#success-placeholder th {'+ - ' width: 10%;'+ - '}'+ - '#success-placeholder table {'+ - ' width: 100%;'+ - '}' - ; - - - -success.report = function report_success(datastorage, sorteddaystoshow, options) { +success.report = function report_success (datastorage, sorteddaystoshow, options) { var Nightscout = window.Nightscout; var client = Nightscout.client; var translate = client.translate; var ss = require('simple-statistics'); - var low = options.targetLow, - high = options.targetHigh; + var low = options.targetLow + , high = options.targetHigh; var data = datastorage.allstatsrecords; - + var now = Date.now(); var period = 7 * times.hours(24).msecs; var firstDataPoint = data.reduce(function(min, record) { - return Math.min(min, record.displayTime); - }, Number.MAX_VALUE); + return Math.min(min, record.displayTime); + }, Number.MAX_VALUE); if (firstDataPoint < 1390000000000) { firstDataPoint = 1390000000000; } @@ -79,39 +73,39 @@ success.report = function report_success(datastorage, sorteddaystoshow, options) if (quarters === 0) { // insufficent data - grid.append('

'+translate('There is not sufficient data to run this report. Select more days.')+'

'); + grid.append('

' + translate('There is not sufficient data to run this report. Select more days.') + '

'); return; } var dim = function(n) { var a = []; for (var i = 0; i < n; i++) { - a[i]=0; + a[i] = 0; } return a; }; var sum = function(a) { - return a.reduce(function(sum,v) { - return sum+v; + return a.reduce(function(sum, v) { + return sum + v; }, 0); }; var averages = { - percentLow: 0, - percentInRange: 0, - percentHigh: 0, - standardDeviation: 0, - lowerQuartile: 0, - upperQuartile: 0, - average: 0 + percentLow: 0 + , percentInRange: 0 + , percentHigh: 0 + , standardDeviation: 0 + , lowerQuartile: 0 + , upperQuartile: 0 + , average: 0 }; quarters = dim(quarters).map(function(blank, n) { - var starting = new Date(now - (n+1) * period), - ending = new Date(now - n * period); + var starting = new Date(now - (n + 1) * period) + , ending = new Date(now - n * period); return { - starting: starting, - ending: ending, - records: data.filter(function(record) { - return record.displayTime > starting && record.displayTime <= ending; + starting: starting + , ending: ending + , records: data.filter(function(record) { + return record.displayTime > starting && record.displayTime <= ending; }) }; }).filter(function(quarter) { @@ -121,8 +115,8 @@ success.report = function report_success(datastorage, sorteddaystoshow, options) return record.sgv; }); quarter.standardDeviation = ss.standard_deviation(bgValues); - quarter.average = bgValues.length > 0? (sum(bgValues) / bgValues.length): 'N/A'; - quarter.lowerQuartile = ss.quantile(bgValues, 0.25); + quarter.average = bgValues.length > 0 ? (sum(bgValues) / bgValues.length) : 'N/A'; + quarter.lowerQuartile = ss.quantile(bgValues, 0.25); quarter.upperQuartile = ss.quantile(bgValues, 0.75); quarter.numberLow = bgValues.filter(function(bg) { return bg < low; @@ -148,9 +142,9 @@ success.report = function report_success(datastorage, sorteddaystoshow, options) var lowComparison = function(quarter, averages, field, invert) { if (quarter[field] < averages[field] * 0.8) { - return (invert? 'bad': 'good'); + return (invert ? 'bad' : 'good'); } else if (quarter[field] > averages[field] * 1.2) { - return (invert? 'good': 'bad'); + return (invert ? 'good' : 'bad'); } else { return ''; } @@ -172,44 +166,44 @@ success.report = function report_success(datastorage, sorteddaystoshow, options) } }; - table.append(''); + table.append(''); table.append('' + quarters.filter(function(quarter) { return quarter.records.length > 0; }).map(function(quarter) { var INVERT = true; return '' + [ - quarter.starting.toLocaleDateString() + ' - ' + quarter.ending.toLocaleDateString(), - { - klass: lowComparison(quarter, averages, 'percentLow'), - text: Math.round(quarter.percentLow) + '%' - }, - { - klass: lowComparison(quarter, averages, 'percentInRange', INVERT), - text: Math.round(quarter.percentInRange) + '%' - }, - { - klass: lowComparison(quarter, averages, 'percentHigh'), - text: Math.round(quarter.percentHigh) + '%' - }, - { - klass: lowComparison(quarter, averages, 'standardDeviation'), - text: (quarter.standardDeviation > 10? Math.round(quarter.standardDeviation): quarter.standardDeviation.toFixed(1)) - }, - { - klass: lowQuartileEvaluation(quarter, averages), - text: quarter.lowerQuartile - }, - { - klass: lowComparison(quarter, averages, 'average'), - text: quarter.average.toFixed(1) - }, - { - klass: upperQuartileEvaluation(quarter, averages), - text: quarter.upperQuartile + quarter.starting.toLocaleDateString() + ' - ' + quarter.ending.toLocaleDateString() + , { + klass: lowComparison(quarter, averages, 'percentLow') + , text: Math.round(quarter.percentLow) + '%' + } + , { + klass: lowComparison(quarter, averages, 'percentInRange', INVERT) + , text: Math.round(quarter.percentInRange) + '%' + } + , { + klass: lowComparison(quarter, averages, 'percentHigh') + , text: Math.round(quarter.percentHigh) + '%' + } + , { + klass: lowComparison(quarter, averages, 'standardDeviation') + , text: (quarter.standardDeviation > 10 ? Math.round(quarter.standardDeviation) : quarter.standardDeviation.toFixed(1)) + } + , { + klass: lowQuartileEvaluation(quarter, averages) + , text: quarter.lowerQuartile + } + , { + klass: lowComparison(quarter, averages, 'average') + , text: quarter.average.toFixed(1) + } + , { + klass: upperQuartileEvaluation(quarter, averages) + , text: quarter.upperQuartile } ].map(function(v) { if (typeof v === 'object') { - return ''; + return ''; } else { return ''; } diff --git a/lib/sandbox.js b/lib/sandbox.js index 3379bf50..ceac9a3f 100644 --- a/lib/sandbox.js +++ b/lib/sandbox.js @@ -4,21 +4,21 @@ var _ = require('lodash'); var units = require('./units')(); var times = require('./times'); -function init ( ) { +function init () { var sbx = {}; - function reset () { - sbx.properties = { }; + function reset () { + sbx.properties = {}; } - function extend ( ) { + function extend () { sbx.unitsLabel = unitsLabel(); sbx.data = sbx.data || {}; //default to prevent adding checks everywhere - sbx.extendedSettings = {empty: true}; + sbx.extendedSettings = { empty: true }; } - function withExtendedSettings(plugin, allExtendedSettings, sbx) { + function withExtendedSettings (plugin, allExtendedSettings, sbx) { var sbx2 = _.extend({}, sbx); sbx2.extendedSettings = allExtendedSettings && allExtendedSettings[plugin.name] || {}; return sbx2; @@ -48,7 +48,7 @@ function init ( ) { sbx.settings = env.settings; sbx.data = ctx.ddata.clone(); sbx.notifications = safeNotifications(ctx); - + sbx.levels = ctx.levels; sbx.language = ctx.language; sbx.translate = ctx.language.translate; @@ -60,7 +60,7 @@ function init ( ) { sbx.data.profile = profile; delete sbx.data.profiles; - sbx.properties = { }; + sbx.properties = {}; sbx.withExtendedSettings = function getPluginExtendedSettingsOnly (plugin) { return withExtendedSettings(plugin, env.extendedSettings, sbx); @@ -89,7 +89,7 @@ function init ( ) { sbx.data = data; sbx.pluginBase = ctx.pluginBase; sbx.notifications = safeNotifications(ctx); - + sbx.levels = ctx.levels; sbx.language = ctx.language; sbx.translate = ctx.language.translate; @@ -99,7 +99,7 @@ function init ( ) { sbx.pluginBase.forecastPoints = []; } - sbx.extendedSettings = {empty: true}; + sbx.extendedSettings = { empty: true }; sbx.withExtendedSettings = function getPluginExtendedSettingsOnly (plugin) { return withExtendedSettings(plugin, sbx.settings.extendedSettings, sbx); }; @@ -116,7 +116,7 @@ function init ( ) { * @param setter */ sbx.offerProperty = function offerProperty (name, setter) { - if (!sbx.properties.hasOwnProperty(name)) { + if (!Object.keys(sbx.properties).includes(name)) { var value = setter(); if (value) { sbx.properties[name] = value; @@ -124,7 +124,7 @@ function init ( ) { } }; - sbx.isCurrent = function isCurrent(entry) { + sbx.isCurrent = function isCurrent (entry) { return entry && sbx.time - entry.mills <= times.mins(15).msecs; }; @@ -137,7 +137,7 @@ function init ( ) { sbx.lastNEntries = function lastNEntries (entries, n) { var lastN = []; - _.takeRightWhile(entries, function (entry) { + _.takeRightWhile(entries, function(entry) { if (sbx.entryMills(entry) <= sbx.time) { lastN.push(entry); } @@ -158,32 +158,32 @@ function init ( ) { return sbx.prevEntry(sbx.data.sgvs); }; - sbx.lastSGVEntry = function lastSGVEntry ( ) { + sbx.lastSGVEntry = function lastSGVEntry () { return sbx.lastEntry(sbx.data.sgvs); }; - sbx.lastSGVMgdl = function lastSGVMgdl ( ) { + sbx.lastSGVMgdl = function lastSGVMgdl () { var last = sbx.lastSGVEntry(); return last && last.mgdl; }; - sbx.lastSGVMills = function lastSGVMills ( ) { + sbx.lastSGVMills = function lastSGVMills () { return sbx.entryMills(sbx.lastSGVEntry()); }; - sbx.entryMills = function entryMills(entry) { + sbx.entryMills = function entryMills (entry) { return entry && entry.mills; }; - sbx.lastScaledSGV = function lastScaledSVG ( ) { + sbx.lastScaledSGV = function lastScaledSVG () { return sbx.scaleEntry(sbx.lastSGVEntry()); }; - sbx.lastDisplaySVG = function lastDisplaySVG ( ) { + sbx.lastDisplaySVG = function lastDisplaySVG () { return sbx.displayBg(sbx.lastSGVEntry()); }; - sbx.buildBGNowLine = function buildBGNowLine ( ) { + sbx.buildBGNowLine = function buildBGNowLine () { var line = 'BG Now: ' + sbx.lastDisplaySVG(); var delta = sbx.properties.delta && sbx.properties.delta.display; @@ -216,7 +216,7 @@ function init ( ) { return lines; }; - sbx.prepareDefaultLines = function prepareDefaultLines() { + sbx.prepareDefaultLines = function prepareDefaultLines () { var lines = [sbx.buildBGNowLine()]; sbx.appendPropertyLine('rawbg', lines); sbx.appendPropertyLine('ar2', lines); @@ -227,7 +227,7 @@ function init ( ) { return lines; }; - sbx.buildDefaultMessage = function buildDefaultMessage() { + sbx.buildDefaultMessage = function buildDefaultMessage () { return sbx.prepareDefaultLines().join('\n'); }; @@ -272,14 +272,10 @@ function init ( ) { if (sbx.properties.roundingStyle === 'medtronic') { var denominator = 0.1; var digits = 1; - if (insulin > 0.5 && iob < 1) { + if (insulin <= 0.5) { denominator = 0.05; digits = 2; } - if (insulin <= 0.5) { - denominator = 0.025; - digits = 3; - } return (Math.floor(insulin / denominator) * denominator).toFixed(digits); } @@ -287,7 +283,7 @@ function init ( ) { }; - function unitsLabel ( ) { + function unitsLabel () { return sbx.settings.units === 'mmol' ? 'mmol/L' : 'mg/dl'; } @@ -299,4 +295,3 @@ function init ( ) { } module.exports = init; - diff --git a/views/nightscout.appcache b/views/nightscout.appcache index 92b7bd50..3823f894 100644 --- a/views/nightscout.appcache +++ b/views/nightscout.appcache @@ -28,6 +28,7 @@ CACHE MANIFEST /css/main.css?v=<%= locals.cachebuster %> /bundle/js/bundle.app.js?v=<%= locals.cachebuster %> /bundle/js/bundle.clock.js?v=<%= locals.cachebuster %> +/bundle/js/bundle.report.js?v=<%= locals.cachebuster %> /socket.io/socket.io.js?v=<%= locals.cachebuster %> /js/client.js?v=<%= locals.cachebuster %> /images/logo2.png diff --git a/webpack.config.js b/webpack.config.js index c6a0acec..5dbb03a8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -115,7 +115,7 @@ if (process.env.NODE_ENV == 'development') { rules.unshift({ enforce: "pre", test: /\.js$/, - exclude: /node_modules/, + exclude: [/node_modules/, /bundle/], loader: "eslint-loader", options: { emitWarning: true,
'+translate('Period')+''+translate('Low')+''+translate('In Range')+''+translate('High')+''+translate('Standard Deviation')+''+translate('Low Quartile')+''+translate('Average')+''+translate('Upper Quartile')+'
' + translate('Period') + '' + translate('Low') + '' + translate('In Range') + '' + translate('High') + '' + translate('Standard Deviation') + '' + translate('Low Quartile') + '' + translate('Average') + '' + translate('Upper Quartile') + '
' + v.text + '' + v.text + '' + v + '