nightscout
Version:
Nightscout acts as a web-based CGM (Continuous Glucose Monitor) to allow multiple caregivers to remotely view a patients glucose data in realtime.
728 lines (638 loc) • 29.6 kB
JavaScript
;
var init = function init () {
//for the tests window isn't the global object
var $ = window.$;
var _ = window._;
var moment = window.moment;
var Nightscout = window.Nightscout;
var client = Nightscout.client;
var c_profile = null;
//some commonly used selectors
var peStatus = $('.pe_status');
var timezoneInput = $('#pe_timezone');
var databaseRecords = $('#pe_databaserecords');
var timeInput = $('#pe_time');
var dateInput = $('#pe_date');
client.init(function loaded () {
if (c_profile !== null) {
return; // already loaded so don't load again
}
var translate = client.translate;
var defaultprofile = {
//General values
'dia':3,
'carbratio': [
{
'time': '00:00',
'value': 30
}]
, 'carbs_hr': 20
, 'delay': 20
, 'sens': [
{
'time': '00:00',
'value': 100
}]
, 'timezone': 'UTC'
//perGIvalues style values
, 'perGIvalues': false
, 'carbs_hr_high': 30
, 'carbs_hr_medium': 30
, 'carbs_hr_low': 30
, 'delay_high': 15
, 'delay_medium': 20
, 'delay_low': 20
, 'basal':[
{
'time': '00:00',
'value': 0.1
}]
, 'target_low':[
{
'time': '00:00',
'value': 0
}]
, 'target_high':[
{
'time': '00:00',
'value': 0
}]
,startDate: new Date(0).toISOString()
};
// , 'startDate': new Date()
// defaultprofile.startDate.setSeconds(0);
// defaultprofile.startDate.setMilliseconds(0);
var icon_add = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABa0lEQVQ4T6WTzysEYRjHP+/Mrv2hHOTuqJRNOfgPSORHokg4OClHcnVzVygHF6WIcuHMnyCHVRyI3ZYxa23vzOzs7LzamaI0e5i89fTWt/f5vPV5n1cQsXLbHepvfLv5JaLORoZNwMbyFo5vYfsWB0c7xAasLa5T/vCg45Oj48P4gJWFVYxCA63L5PzkND5gfm4Jo+Chd5W5OrtsDYgS1pQ1OTuNUfTQO8tcX9xE+QugYnS/X81MzGP7MpTWkEFVZY1KxcVPV3h27zAtA+oCagIcDfWUCgEje31qfHwK06gHjaF5iXQcHCV5lHmqqgQCNEAI0IsavCVDwNBurxoeGwmaAkDDwvYsqtIh//6AJUoklP97s62BbJYeAqIcpJNZsoM+r2aVbKKOekiBL8An3BuAEiGg1SSKAYnttpFxPdR9Jv4zipxFTUuQKqsfYbFGWfTYuO06yRfxIyweoLuG+iMsFuBfvzFy7FqE33vs2BFqlfN5AAAAAElFTkSuQmCC';
var icon_remove = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACrElEQVQ4T42Ty2sTQRzHv5tmk2yyjRNtpfZhL8V6s2KoUNC2XqwgaCsVQcGiFqpHi0c9iRdR/ANE9KR40FIQX4cueKoPaKFoLdSYNtE0abKT1+5s9iW7aUMiHtzTzO7v85md+c6PA4DrHbsPCKIgOWO1pA7dT6YXnXH949SE/F63pqwZtRrO+SCKgjQ5NUV+azpmHj2krMwaJC4c8Erj+/eRyloMMwWFKgbn1nC3ervlK1evkXBLGBZT8SOewotnTylTNLdgeg/pDgZDC2cPHSR8bB22DVC9hFe0SG/H0xFXcHlykjRHRDBWgJcZSCY38Xx2lhqMnRYE34Px/sN9vlQWeoHBAx2yXsRruVAVuFsIBaSJ8+eJGPaBqQV4NROJjTzez89jLBoFn6FgybQL54wS3uTyVDFQ3cL2IYpBv3RhdJSIIQ80tQyv7gEqJvS8AmUlBs7UXPhtjtZgh3UFNYngk86NHCfNAg9dMwHVBPu+CpsVkTXKeJeVG+AGgTOZ3tt6MSKKjy+NjEBjFrR4ElZmA4pdxstMFsyyJu6tZZ7Ux9vwB6EAL50ZGiRECEPPUOixVTRxHlicgSVWxEdZpuZWfNuS2hk48NjwMIkIYZglBnV5Cbqtws/5IaAJmsfCglrEl2y2QeKmEBJ80tixKmxrFpSVr0gV0viQoxho2YUuPohmeFD22PiklLC4ma5JuBvdrfLJI0dJd0s7bM0ES8aR/BXDXGaTskqlL+D3Lwy0tZEePoAd4EA5YF4tYymdonfjmQh3s6dTPjU4SHYGwjAKecSXFyGlM1TdytntE56T+ts7SC/vhw3gm6njc2Kd3vm5Ub1IwQAvnYhGiZpYw1wiWYPrIw7wnBTt7CLOOwdmut14kQQvqt24tfK/utGR6LaF+iRqMf4N/O/8D28HiiCRYqzAAAAAAElFTkSuQmCC';
//var icon_clone = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACSklEQVQ4T5VTYU9SYRR+zn0vXhDEFyRBXcpmbZnZsOXsI2xpVnNcv/ilufET8h/oL8h/gN/aWhs2yjKt26rPSvUh5yQodQlqgKQCd5fbLg2jxlycT+/OOc85z/OcvYSa8MoRLqimUEuzOSgwBl0nFFUtW1K1J/Ho6Hxtr/H2yQqnarJ3fFHucNnC57tdXIUJhydl6CAwIhwfFXCwf5hUC6XpjYXAQgUcUngRzkxlgHc0Kl+57I443S7s5VQwxqCVCYVSGfkTFSQQmsQmHGVzKJ78nJMs2izBohRg8ZFB293iSPQPdPOiqiOdyiGdysdKmp4t64LXxlu9otUKTVdhkSSUjgooHOez7R1uvr2bA10cfx66cb0n3GS14tPHrWz6R34i+fT2m6q0rruv7tvs9gdOtxNk0mA2SRB0gqVZwGb8AOSbXIkMDV+Qt7cy2IinJ+LRWxWNf5ur+Kx2vub0OABRg2QSIYqEr/EMaHjqrdJ/tce/upqIxR76B/8FVzySFc7MzWvtnW6vyjSAAFFgyBkSrt17n7jU1+ldjcVn1x+PzNTZzkWLTXF5zvmYmaEslCEIxnUE7H07AA1NvVPaO9r8X5Kpic+Pfp+oNvpCH/R6rKo5GphUIq1Oh7y++T2wv/LHvLNAtTXqHX8Zkqyt4XQ6M73/emzuf4GnDLg/wu0tbYliqTifWhqZbniAAfCMLs/oRMHU0s26VzjTA6PI/QqXJC1BxAZ3XwSSjbA4/UyesWU/Y2Jw51mgIRmnA4ytXXcU385iINYIg1+OJdcoyf/hkgAAAABJRU5ErkJggg==';
//var icon_apply = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACh0lEQVQ4T5XSXUhTYRgH8P85O+fMOZ3H2WButc7MD3AQWyaYIRZEqANpt9HHCiwvIhWim8gPiqArJailVmdhJGEI3USk4rAQc1MnTdMitZhtfm86ncvcYhMls2i9l+/Hj//zvA+B/1kmcKSArGIohmNIZoIMkRVE1O95sOQaOXCCK+KUYgWcy99gne2zRA1Q9VR1/u7DVcVcIdyrLshFCtQPNyIqgG6gtWImduB69lVM+r9EQqvEajQM8dEBokcxnSWas0fSElMw5B1EdlIuLM43GJxz1P0zgfhhjDFDmsFf1pVixOeASqTGgt+Llk+tEwCt2wDuQgsSWghgxwXYNxvL8iwbIoLjN3KvsQQVRCAUgIyWg3c0wRdYPmoz2C0E7qE2NUFdnpa4D73TfZgLLNThIirCCGuW8MWpRcYC9TF8DYwhPU6DtvEO2Kb666zF9sidMBC6lVsJES1EiCDwZPQZHHMfzBJB7ONdcbLOm3mVcP9wQi5UwO2bQdP7pxOi9aDOYrB7NgATQnfyb2Mq4AJN0eDiU9A82oL+6UFcyS7DXqkSfixDKpDB1P8Ai98Xdd1661aZBO6jNif5YPm5zFOYXZsCQzHYE8dhZP4jspK1mAm6oYpR49Xn1+iZtNW81fdU/zp8kSaSDSSfpzxkPK85jfn1WawSK9BI9mMJXkiFSXAvzYAfMNu79O90v0/u1jdKzPER5IzmJLyhefiJFchFyWApKUzWRnj8Hp1F370VfRPaNgfKZgWfIlEZL2WVQsAASUIZ2sY60Ou01bQXdm2L/kcgvJn5PJ3nElTG0qwSuHwutAy32tsLunZE/ysQPsh5caCaoYRlQgHjoUnC8PK4ZUf0TeAnGJ/iJEGClrwAAAAASUVORK5CYII=';
var mongorecords = [];
var currentrecord = 0;
var currentprofile = null;
var dirty = false;
// Fetch data from mongo
peStatus.hide().text(translate('Loading profile records ...')).fadeIn('slow');
$.ajax('/api/v1/profile.json?count=20', {
headers: client.headers()
, success: function (records) {
if (!records.length) {
records.push(defaultprofile);
}
client.profilefunctions.loadData(records); // do a conversion if needed
mongorecords = _.cloneDeep(client.profilefunctions.data);
// create new profile to be edited from last record
if (mongorecords.length) {
_.each(mongorecords, function eachMongoProfile (mongoprofile) {
_.each(mongoprofile.store, function eachStoredProfile (p) {
// allign with default profile
for (var key in defaultprofile) {
if (Object.prototype.hasOwnProperty.call(defaultprofile,key) && !Object.prototype.hasOwnProperty.call(p,key)) {
p[key] = defaultprofile[key];
}
}
for (key in p) {
if (Object.prototype.hasOwnProperty.call(p,key) && !Object.prototype.hasOwnProperty.call(defaultprofile,key)) {
delete p[key];
}
}
convertToRanges(p);
});
});
peStatus.hide().text(translate('Values loaded.')).fadeIn('slow');
} else {
mongorecords.push({
defaultProfile: 'Default'
, store : {
'Default': _.cloneDeep(defaultprofile)
}
, startDate: new Date().toISOString()
});
peStatus.hide().text(translate('Default values used.')).fadeIn('slow');
}
}
, error: function () {
mongorecords.push({
defaultProfile: 'Default'
, store : {
'Default': _.cloneDeep(defaultprofile)
}
, startDate: new Date().toISOString()
});
peStatus.hide().text(translate('Error. Default values used.')).fadeIn('slow');
}
}).done(initeditor);
// convert simple values to ranges if needed
function convertToRanges(profile) {
if (typeof profile.carbratio !== 'object') { profile.carbratio = [{ 'time': '00:00', 'value': profile.carbratio }]; }
if (typeof profile.sens !== 'object') { profile.sens = [{ 'time': '00:00', 'value': profile.sens }]; }
if (typeof profile.target_low !== 'object') { profile.target_low = [{ 'time': '00:00', 'value': profile.target_low }]; }
if (typeof profile.target_high !== 'object') { profile.target_high = [{ 'time': '00:00', 'value': profile.target_high }]; }
if (typeof profile.basal !== 'object') { profile.basal = [{ 'time': '00:00', 'value': profile.basal }]; }
if (profile.target_high.length !== profile.target_low.length) {
window.alert(translate('Time ranges of target_low and target_high don\'t match. Values are restored to defaults.'));
profile.target_low = _.cloneDeep(defaultprofile.target_low);
profile.target_high = _.cloneDeep(defaultprofile.target_high);
}
}
function initeditor() {
$('#pe_history').toggle(client.settings.extendedSettings.profile && client.settings.extendedSettings.profile.history);
$('#pe_multiple').toggle(client.settings.extendedSettings.profile && client.settings.extendedSettings.profile.multiple);
// Load timezones
timezoneInput.empty();
moment.tz.names().forEach(function addTz(tz) {
timezoneInput.append('<option value="' + tz + '">' + tz + '</option>');
});
$('#pe_form').find('button').click(profileSubmit);
$('#pe_profiles').unbind().bind('change', profileChange);
$('#pe_profile_add').unbind().bind('click', profileAdd);
$('#pe_profile_remove').unbind().bind('click', profileRemove);
$('#pe_profile_clone').unbind().bind('click', profileClone);
$('#pe_databaserecords').unbind().bind('change',recordChange);
$('#pe_records_add').unbind().bind('click', recordAdd);
$('#pe_records_remove').unbind().bind('click', recordRemove);
$('#pe_records_clone').unbind().bind('click', recordClone);
// Add handler for style switching
$('#pe_perGIvalues').unbind().on('change', switchStyle);
// display status
$('#pe_units').text(client.settings.units);
$('#pe_timeformat').text(client.settings.timeFormat+'h');
$('#pe_title').text(client.settings.customTitle);
currentprofile = mongorecords[currentrecord].defaultProfile;
// prepare basal profiles
initRecord();
// hide unused style of ratios
switchStyle();
console.log('Done initeditor()');
}
function initRecord() {
databaseRecords.empty();
for (var r = 0; r < mongorecords.length; r++ ) {
databaseRecords.append('<option value="' + r + '">' + translate('Valid from:') + ' ' + new Date(mongorecords[r].startDate).toLocaleString() + '</option>');
}
databaseRecords.val(currentrecord);
timeInput.val(moment(mongorecords[currentrecord].startDate).format('HH:mm'));
dateInput.val(moment(mongorecords[currentrecord].startDate).format('YYYY-MM-DD'));
initProfile();
}
function timeDiffMinutes(time1, time2)
{
var minutes1 = toMinutesFromMidnight(time1);
var minutes2 = toMinutesFromMidnight(time2);
if (minutes2 <= minutes1) {
minutes2 += 24*60;
}
return minutes2-minutes1;
}
function refreshTotalBasal()
{
GUIToObject();
var total = 0;
for (var i=0, len=c_profile['basal'].length; i<len; i++) {
var time1 = c_profile['basal'][i].time;
var time2 = c_profile['basal'][(i+1)%len].time;
var value = c_profile['basal'][i].value;
total += timeDiffMinutes(time1,time2) * value / 60
}
$('#pe_basalTotal_placeholder').html(Math.round(total*1000)/1000);
}
function initProfile() {
var record = mongorecords[currentrecord];
// fill profilenames
$('#pe_profiles').empty();
for (var key in record.store) {
if (Object.prototype.hasOwnProperty.call(record.store,key)) {
$('#pe_profiles').append('<option value="' + key + '">' + key + '</option>');
}
}
$('#pe_profiles').val(currentprofile);
$('#pe_profile_name').val(currentprofile);
c_profile = mongorecords[currentrecord].store[currentprofile];
mongorecords[currentrecord].defaultProfile = currentprofile;
// Set values from profile to html
fillTimeRanges();
refreshTotalBasal();
}
// Handling of record list box change
function recordChange (event) {
if (dirty && window.confirm(translate('Save current record before switching to new?'))) {
profileSubmit();
}
currentrecord = databaseRecords.val();
currentprofile = mongorecords[currentrecord].defaultProfile;
initRecord();
dirty = false;
maybePreventDefault(event);
}
function recordAdd (event) {
if (dirty && window.confirm(translate('Save current record before switching to new?'))) {
profileSubmit();
}
mongorecords.push({
startDate: new Date().toISOString()
, defaultProfile: 'Default'
, store: {
'Default' : _.cloneDeep(defaultprofile)
}
});
currentrecord = mongorecords.length - 1;
currentprofile = 'Default';
initRecord();
dirty = true;
maybePreventDefault(event);
}
function recordRemove (event) {
if (mongorecords.length > 1 && window.confirm(translate('Delete record')+'?')) {
if (mongorecords[currentrecord]._id) {
$.ajax({
method: 'DELETE'
, url: '/api/v1/profile/'+mongorecords[currentrecord]._id
, headers: client.headers()
}).done(function postSuccess () {
console.info('profile deleted');
peStatus.hide().text(status).fadeIn('slow');
mongorecords.splice(currentrecord,1);
currentrecord = 0;
currentprofile = mongorecords[currentrecord].defaultProfile;
initRecord();
dirty = false;
}).fail(function(xhr, status, errorThrown) {
console.error('Profile not removed', status, errorThrown);
peStatus.hide().text(status).fadeIn('slow');
});
} else {
mongorecords.splice(currentrecord,1);
currentrecord = 0;
currentprofile = mongorecords[currentrecord].defaultProfile;
initRecord();
dirty = false;
}
}
maybePreventDefault(event);
return false;
}
function recordClone (event) {
if (dirty && window.confirm(translate('Save current record before switching to new?'))) {
profileSubmit();
}
GUIToObject();
mongorecords.push(_.cloneDeep(mongorecords[currentrecord]));
currentrecord = mongorecords.length - 1;
mongorecords[currentrecord].startDate = new Date().toISOString();
currentprofile = mongorecords[currentrecord].defaultProfile;
delete mongorecords[currentrecord]._id;
initRecord();
dirty = true;
maybePreventDefault(event);
}
// Handling of profile list box change
function profileChange (event) {
var record = mongorecords[currentrecord];
var newpr = $('#pe_profiles').val();
// copy values from html to c_profile
GUIToObject();
var newname = $('#pe_profile_name').val();
if (!isNaN(newname)) newname = 'Profile' + newname;
if (currentprofile !== newname) {
// rename if already exists
while (record.store[newname]) {
newname += '1';
}
record.store[newname] = record.store[currentprofile];
delete record.store[currentprofile];
dirty = true;
}
if (newpr === currentprofile) { // fake call to update values
newpr = newname;
}
currentprofile = newpr;
initProfile();
maybePreventDefault(event);
return false;
}
function profileAdd (event) {
var record = mongorecords[currentrecord];
var newname = 'New profile';
while (record.store[newname]) {
newname += '1';
}
record.store[newname] = _.cloneDeep(defaultprofile);
currentprofile = newname;
dirty = true;
initProfile();
maybePreventDefault(event);
return false;
}
function profileRemove (event) {
var record = mongorecords[currentrecord];
var availableProfile = getFirstAvailableProfile(record);
if (availableProfile) {
delete record.store[currentprofile];
currentprofile = availableProfile;
initProfile();
dirty = true;
}
maybePreventDefault(event);
return false;
}
function profileClone (event) {
GUIToObject();
var record = mongorecords[currentrecord];
var newname = $('#pe_profile_name').val() + ' (copy)';
while (record.store[newname]) {
newname += '1';
}
record.store[newname] = _.cloneDeep(record.store[currentprofile]);
currentprofile = newname;
dirty = true;
initProfile();
maybePreventDefault(event);
return false;
}
// Handling html events and setting/getting values
function switchStyle(event) {
if (!$('#pe_perGIvalues').is(':checked')) {
$('#pe_simple').show('slow');
$('#pe_advanced').hide('slow');
} else {
$('#pe_simple').hide('slow');
$('#pe_advanced').show('slow');
}
maybePreventDefault(event);
}
function fillTimeRanges(event) {
if (event) {
GUIToObject();
}
function shouldAddTime(i, time, array) {
if (i === 0 && time === 0) {
return true;
} else if (i === 0) {
return false;
} else {
var minutesFromMidnight = toMinutesFromMidnight(c_profile[array][i - 1].time);
return !isNaN(minutesFromMidnight) && minutesFromMidnight < time * 30;
}
}
function addSingleLine(e,i) {
var tr = $('<tr>');
var select = $('<select>').attr('class','pe_selectabletime').attr('id',e.prefix+'_from_'+i);
var lowest = -1;
for (var t=0;t<48;t++) {
if (shouldAddTime(i, t, e.array)) {
if (lowest === -1) { lowest = t*30; }
select.append('<option value="' + toTimeString(t*30) + '">' + toDisplayTime(t*30) + '</option>');
}
}
var selectedValue = toMinutesFromMidnight(c_profile[e.array][i].time) * 30;
select.val(selectedValue);
tr.append($('<td>').append(translate('From') + ': ').append(select));
tr.append($('<td>').append(e.label).append($('<input type="text">').attr('id',e.prefix+'_val_'+i).attr('value',c_profile[e.array][i].value).attr('class', e.prefix + '_value')));
var icons_td = $('<td>').append($('<img>').attr('class','addsingle').attr('style','cursor:pointer').attr('title',translate('Add new interval before')).attr('src',icon_add).attr('array',e.array).attr('pos',i));
if (c_profile[e.array].length>1) {
icons_td.append($('<img>').attr('class','delsingle').attr('style','cursor:pointer').attr('title',translate('Delete interval')).attr('src',icon_remove).attr('array',e.array).attr('pos',i));
}
tr.append(icons_td);
if (lowest>toMinutesFromMidnight(c_profile[e.array][i].time)) {
c_profile[e.array][i].time = toTimeString(lowest);
}
return tr[0].outerHTML;
}
// Fill dropdown boxes
_.each([{prefix:'pe_basal', array:'basal', label: translate('Basal rate') + ' : '},
{prefix:'pe_ic', array:'carbratio', label: translate('I:C') + ' : '},
{prefix:'pe_isf', array:'sens', label: translate('ISF') + ' : '}
], function (e) {
var html = '<table>';
for (var i=0; i<c_profile[e.array].length; i++) {
html += addSingleLine(e,i);
}
html += '<tr><td></td><td></td><td><img class="addsingle" style="cursor:pointer" title="' + translate('Add new interval before') + '" src="'+icon_add+'" array="'+e.array+'" pos="'+i+'" href="#"></td></tr>';
html += '</table>';
$('#'+e.prefix+'_placeholder').html(html);
});
$('.pe_basal_value').on('change keyup paste', refreshTotalBasal);
$('.addsingle').click(function addsingle_click() {
var array = $(this).attr('array');
var pos = $(this).attr('pos');
GUIToObject();
c_profile[array].splice(pos,0,{time:'00:00',value:0});
var retVal = fillTimeRanges();
refreshTotalBasal();
return retVal;
});
$('.delsingle').click(function delsingle_click() {
var array = $(this).attr('array');
var pos = $(this).attr('pos');
GUIToObject();
c_profile[array].splice(pos,1);
c_profile[array][0].time = '00:00';
var retVal = fillTimeRanges();
refreshTotalBasal();
return retVal;
});
function addBGLine(i) {
var tr = $('<tr>');
var select = $('<select>').attr('class','pe_selectabletime').attr('id','pe_targetbg_from_'+i);
var lowesttime=-1;
for (var t=0;t<48;t++) {
if (shouldAddTime(i, t, 'target_low')) {
if (lowesttime === -1) { lowesttime = t*30; }
select.append('<option value="' + toTimeString(t*30) + '">' + toDisplayTime(t*30) + '</option>');
}
}
var selectedValue = toMinutesFromMidnight(c_profile.target_low[i].time) * 30;
select.val(selectedValue);
tr.append($('<td>').append(translate('From') + ': ').append(select));
tr.append($('<td>').append(translate('Low') + ' : ').append($('<input type="text">').attr('id','pe_targetbg_low_'+i).attr('value',c_profile.target_low[i].value)));
tr.append($('<td>').append(translate('High') + ' : ').append($('<input type="text">').attr('id','pe_targetbg_high_'+i).attr('value',c_profile.target_high[i].value)));
var icons_td = $('<td>').append($('<img>').attr('class','addtargetbg').attr('style','cursor:pointer').attr('title',translate('Add new interval before')).attr('src',icon_add).attr('pos',i));
if (c_profile.target_low.length>1) {
icons_td.append($('<img>').attr('class','deltargetbg').attr('style','cursor:pointer').attr('title',translate('Delete interval')).attr('src',icon_remove).attr('pos',i));
}
tr.append(icons_td);
// Fix time to correct value after add or change
if (lowesttime>toMinutesFromMidnight(c_profile.target_low[i].time)) {
c_profile.target_low[i].time = toTimeString(lowesttime);
}
return tr[0].outerHTML;
}
// target BG
var html = '<table>';
for (var i=0; i<c_profile.target_low.length; i++) {
html += addBGLine(i);
}
html += '<tr><td></td><td></td><td></td><td><img class="addtargetbg" style="cursor:pointer" title="' + translate('Add new interval before') + '" src="'+icon_add+'" pos="'+i+'" href="#"></td></tr>';
html += '</table>';
$('#pe_targetbg_placeholder').html(html);
$('.addtargetbg').click(function addtargetbg_click() {
var pos = $(this).attr('pos');
GUIToObject();
c_profile.target_low.splice(pos,0,{time:'00:00',value:0});
c_profile.target_high.splice(pos,0,{time:'00:00',value:0});
dirty = true;
return fillTimeRanges();
});
$('.deltargetbg').click(function deltargetbg_click() {
var pos = $(this).attr('pos');
GUIToObject();
c_profile.target_low.splice(pos,1);
c_profile.target_high.splice(pos,1);
c_profile.target_low[0].time = '00:00';
c_profile.target_high[0].time = '00:00';
dirty = true;
return fillTimeRanges();
});
$('.pe_selectabletime').unbind().on('change', fillTimeRanges).on('change', refreshTotalBasal);
objectToGUI();
maybePreventDefault(event);
return false;
}
// fill GUI with values from c_profile object
function objectToGUI() {
$('#pe_dia').val(c_profile.dia);
$('#pe_hr').val(c_profile.carbs_hr);
$('#pe_perGIvalues').prop('checked', c_profile.perGIvalues);
$('#pe_hr_high').val(c_profile.carbs_hr_high);
$('#pe_hr_medium').val(c_profile.carbs_hr_medium);
$('#pe_hr_low').val(c_profile.carbs_hr_low);
$('#pe_delay_high').val(c_profile.delay_high);
$('#pe_delay_medium').val(c_profile.delay_medium);
$('#pe_delay_low').val(c_profile.delay_low);
timezoneInput.val(c_profile.timezone);
var index;
[ { prefix:'pe_basal', array:'basal' },
{ prefix:'pe_ic', array:'carbratio' },
{ prefix:'pe_isf', array:'sens' }
].forEach(function (e) {
for (index=0; index<c_profile[e.array].length; index++) {
$('#'+e.prefix+'_from_'+index).val(c_profile[e.array][index].time);
$('#'+e.prefix+'_val_'+index).val(c_profile[e.array][index].value);
}
});
for (index=0; index<c_profile.target_low.length; index++) {
$('#pe_targetbg_from_'+index).val(c_profile.target_low[index].time);
$('#pe_targetbg_low_'+index).val(c_profile.target_low[index].value);
$('#pe_targetbg_high_'+index).val(c_profile.target_high[index].value);
}
//console.info(JSON.stringify(c_profile));
}
// Grab values from html GUI to object
function GUIToObject() {
var oldProfile = _.cloneDeep(c_profile);
c_profile.units = client.settings.units;
c_profile.dia = parseFloat($('#pe_dia').val());
c_profile.carbs_hr = parseInt($('#pe_hr').val());
c_profile.delay = 20;
c_profile.perGIvalues = $('#pe_perGIvalues').is(':checked');
c_profile.carbs_hr_high = parseInt($('#pe_hr_high').val());
c_profile.carbs_hr_medium = parseInt($('#pe_hr_medium').val());
c_profile.carbs_hr_low = parseInt($('#pe_hr_low').val());
c_profile.delay_high = parseInt($('#pe_delay_high').val());
c_profile.delay_medium = parseInt($('#pe_delay_medium').val());
c_profile.delay_low = parseInt($('#pe_delay_low').val());
c_profile.timezone = timezoneInput.val();
var index;
[ { prefix:'pe_basal', array:'basal' },
{ prefix:'pe_ic', array:'carbratio' },
{ prefix:'pe_isf', array:'sens' }
].forEach(function (e) {
for (index=0; index<c_profile[e.array].length; index++) {
c_profile[e.array][index].time = $('#'+e.prefix+'_from_'+index).val();
c_profile[e.array][index].value = parseFloat($('#'+e.prefix+'_val_'+index).val());
}
});
for (index=0; index<c_profile.target_low.length; index++) {
var input = $('#pe_targetbg_from_' + index);
c_profile.target_low[index].time = input.val();
c_profile.target_low[index].value = parseFloat($('#pe_targetbg_low_'+index).val());
c_profile.target_high[index].time = input.val();
c_profile.target_high[index].value = parseFloat($('#pe_targetbg_high_'+index).val());
}
if (!_.isEqual(oldProfile,c_profile)) {
dirty = true;
}
}
function toMinutesFromMidnight(time) {
var split = time.split(':');
return parseInt(split[0])*60 + parseInt(split[1]);
}
function toTimeString(minfrommidnight) {
return moment.utc().startOf('day').add(minfrommidnight,'minutes').format('HH:mm'); // using utc to avoid daylight saving offset
}
function toDisplayTime (minfrommidnight) {
var time = moment.utc().startOf('day').add(minfrommidnight,'minutes'); // using utc to avoid daylight saving offset
return client.settings.timeFormat === 24 ? time.format('HH:mm') : time.format('h:mm A');
}
function profileSubmit(event) {
if (!client.hashauth.isAuthenticated()) {
window.alert(translate('Your device is not authenticated yet'));
return false;
}
profileChange(event);
var record = mongorecords[currentrecord];
record.startDate = new Date(client.utils.mergeInputTime(timeInput.val(), dateInput.val())).toISOString( );
var adjustedRecord = _.cloneDeep(record);
for (var key in adjustedRecord.store) {
if (Object.prototype.hasOwnProperty.call(adjustedRecord.store,key)) {
var profile = adjustedRecord.store[key];
if (!profile.perGIvalues) {
delete profile.perGIvalues;
delete profile.carbs_hr_high;
delete profile.carbs_hr_medium;
delete profile.carbs_hr_low;
delete profile.delay_high;
delete profile.delay_medium;
delete profile.delay_low;
}
}
}
adjustedRecord.defaultProfile = currentprofile;
adjustedRecord.units = client.settings.units;
delete record.convertedOnTheFly;
delete adjustedRecord.convertedOnTheFly;
console.info('saving profile');
peStatus.hide().text(translate('Saving profile')).fadeIn('slow');
// Hide the form until the ajax PUT is done.
// This is a crude way of preventing the user from changing the inputs whilst waiting.
// If the user was able to make changes, they'd be lost when the done callback redraws anyway.
$('#pe_form').hide();
var headers = client.headers();
headers['Content-Type'] = 'application/json';
$.ajax({
method: 'PUT'
, url: '/api/v1/profile/'
, data: JSON.stringify(adjustedRecord)
, headers: headers
}).done(function postSuccess (data, status) {
console.info('profile saved', data);
$('#pe_form').show(); // allow edits again
peStatus.hide().text(status).fadeIn('slow');
record._id = data._id;
initRecord();
dirty = false;
}).fail(function(xhr, status, errorThrown) {
console.error('Profile not saved', status, errorThrown);
$('#pe_form').show(); // allow edits again
peStatus.hide().text(status).fadeIn('slow');
});
return false;
}
function getFirstAvailableProfile(record) {
var availableProfiles = [];
for (var key in record.store) {
if (Object.prototype.hasOwnProperty.call(record.store,key)) {
if (key !== currentprofile) {
availableProfiles.push(key);
}
}
}
return availableProfiles.length ? availableProfiles[0] : null;
}
function maybePreventDefault (event) {
if (event) {
event.preventDefault();
}
}
});
};
module.exports = init;