const year = new Date().getFullYear(); const HTTP_PATH = "https://newlifemedicalcenters.mybodysite.com"; const AJAXURI = HTTP_PATH + "/ajax"; const HOME_URI = HTTP_PATH + "/"; var subdomainCompanyName = "New Life Health"; var subdomainLogoFile = "https://newlifemedicalcenters.mybodysite.com/img/newlifemedicalcenters-logo-1704406989.png"; var subdomainSplashFile = "https://newlifemedicalcenters.mybodysite.com/img/www-splash.jpg"; var subdomainFaviconFile = "https://newlifemedicalcenters.mybodysite.com/img/icon/newlifemedicalcenters-favicon-1666892938.png"; var subdomainCompanyTagLine = "Your Journey to a New Life"; var versionNum = "3.02.479.01"; var subdomainCopyrightText = "© " + year + " New Life Medical Centers - All Rights Reserved
Rev "+versionNum+"
Technical Support"; var scriptbase = HTTP_PATH+"/js/"; var previewuri = HTTP_PATH+'/preview/'; var imagebrowser = HTTP_PATH+'/image_browser/'; var accountType = null; var ismobile = !!(navigator.userAgent.match(/Android|webOS|iPhone|iPod|iPad|Blackberry/i)); var windowname = ""; window.name = ( windowname !== '' ) ? windowname : generateUUID(); var daysOfTheWeek = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; var mealList = ['Breakfast','Snack 1','Lunch','Snack 2','Dinner','Snack 3']; var exerciseMetric0Descriptors = ['reps', 'mile', 'km', 'bpm', 'lb', '% of max', '% body weight', 'second', 'minute', 'hour']; var exerciseMetric2Descriptors = ['lb', '% of max', '% body weight', 'second', 'minute', 'hour']; var fitbitLogo = '/img/Fitbit_logo_RGB.png'; var inbodyLogo = '/img/inbody_logo.jpeg'; var withingsLogo = '/img/logo_withings_black.png'; const WISTIA_LOGO = '/img/wistia-logo.png'; const WISTIA_ICON = '/img/wistia-logo-flags.png'; const STRIPE_LOGO = '/img/Stripe logo - blue.png'; const FULLSCRIPT_LOGO = '/img/fullscript_logo.png'; const INNOTECH_LOGO = '/img/innotech_logo.png'; const GOOGLE_CAL_LOGO = '/img/Google_Calendar.png'; const OFFICE365_LOGO = '/img/office_365_logo_sm.png'; const MS_EXCHANGE_LOGO = '/img/exchange_logo_sm.png'; const APPLE_HEALTH_LOGO = '/img/Icon - Apple Health.png'; const RUPA_HEALTH_LOGO = '/img/rupa_health_logo.svg'; const OURA_LOGO = '/img/oura_logo.png'; const IGLUCOSE_LOGO = '/img/iGlucose.png'; const ICLOUD_LOGO = '/img/icloud.png'; var PATIENT = "Patient"; const PROVIDER = "Provider"; // user status constants const USER_STATUS_ACTIVATED = parseInt("1"); const USER_STATUS_DEACTIVATED = parseInt("0"); const USER_STATUS_UNACTIVATED = parseInt("2"); const USER_STATUS_PROVIDER_CREATED_UNACTIVATED = parseInt("5"); const USER_STATUS_ADMIN_CREATED_UNACTIVATED = parseInt("6"); const USER_STATUS_DISABLE_ACTIVATION_EMAILS = parseInt("7"); const USER_STATUS_PROVIDER_CREATED_ACTIVATED = parseInt("8"); const USER_SELF_ENROLLMENT = parseInt("10"); const USER_STATUS_PROVIDER_CREATED_DEACTIVATED = parseInt("9"); const USER_STATUS_NEEDS_EMAIL_VALIDATION = parseInt("11"); const SERVER_NAME = "www.mybodysite.com"; const NO_PHOTO = "https://newlifemedicalcenters.mybodysite.com/img/no-photo.png"; const NO_PLAN_PHOTO = "https://newlifemedicalcenters.mybodysite.com/img/no-plan-photo-thumbnail.png"; const NO_PHOTO_THUMBNAIL = "https://newlifemedicalcenters.mybodysite.com/img/no-photo-thumbnail.png"; const MISSING_PHOTO = "https://newlifemedicalcenters.mybodysite.com/img/missing-photo.png"; const MAX_Z_INDEX = 2147483647; const MAX_FILE_SIZE = 10485760; // 10MB const BUTTON_WAITER = '/img/button-busy.gif'; const FITNESS_PLANS_TEMPLATES_OWNER = parseInt("19686"); const NUTRIENTS = ['calories', 'fat', 'satfat', 'cholesterol', 'sodium', 'carb', 'fiber', 'sugar', 'protein', 'calcium']; const ACCOUNT_TYPE_STRING = { 'P' : PROVIDER, 'S': 'Staff', 'U': PATIENT }; const GENDER_STRING = { 'm': 'Male', 'f': 'Female' }; const BACKGROUND_CLASSES = ['bg-primary', 'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning', 'bg-info', 'bg-light', 'bg-dark', 'bg-white']; const MAX_SESSION_LENGTH = 30 * 60; // should be 15 const TIMEOUT_WARNING_LENGTH = 5 * 60; // 5 minutes const WISTIA_ACCESS_TOKEN = "535dd44c756c56cedc21e7f84a539e472abe20531818ee332062d5f6d4c87d42"; const ACTION_CHOICES = [ { action: 'Track a biometric', endpoint: '/save_new_body_log/' }, { action: 'Log an activity', endpoint: '/save_activity/' }, { action: 'Add a biometric goal', endpoint: '/save_body_goal/' }, { action: 'Write in your journal', endpoint: '/save_journal_entry/' }, { action: 'Send a message', endpoint: '/send_private_message_to_staff/' }, { action: 'Confirm some personal info', endpoint: '/update_user_info/' }, { action: 'Set a calorie goal', endpoint: '/set_user_calorie_goal/' }, { action: 'Log in', endpoint: '/login_attempt/' }, { action: 'Create a custom action', endpoint: 'custom' } ]; const TASK_REMIND_TIME_CHOICES = [ { value: 1, text: '1:00' }, { value: 2, text: '2:00' }, { value: 3, text: '3:00' }, { value: 4, text: '4:00' }, { value: 5, text: '5:00' }, { value: 6, text: '6:00' }, { value: 7, text: '7:00' }, { value: 8, text: '8:00' }, { value: 9, text: '9:00' }, { value: 10, text: '10:00' }, { value: 11, text: '11:00' }, { value: 0, text: '12:00' } ]; const ONE_PER_DAY_TASKS = ['/save_new_body_log/', '/save_body_goal/', '/save_activity/', '/update_user_info/', '/set_user_calorie_goal/', '/track_steps/', '/track_sleep/', '/track_water/', '/track_custom_activity/']; const PLAN_ENDING_OPTIONS = [ { label: 'Do nothing', value: 'null' }, { label: 'Repeat once', value: 'REPEAT_PLAN_ONCE' }, { label: 'Repeat indefinitely', value: 'REPEAT_PLAN_INDEFINITELY' }, { label: 'Remove access to this plan', value: 'DEACTIVATE_PLAN' }, { label: 'Deactivate their account', value: 'DEACTIVATE_ACCOUNT' }, { label: 'Assign another plan', value: 'ASSIGN_ANOTHER_PLAN' } ]; const BASE_APP_ITUNES_LINK = 'https://itunes.apple.com/us/app/bodysite-lifestyle-guide/id1084902150?mt=8'; const GOOGLE_PLAY_LINK_PREFIX = 'http://play.google.com/store/apps/details?id='; const BASE_APP_ANDROID_PACKAGE_ID = 'com.bodysite.bodysite'; const LAUNCH_MOBILE_APP_LINK = 'bodysite://launch'; const BLOOD_PRESSURE_METRIC_ID = 15; const DEMO_ACCOUNT_USER_ID = parseInt("358780"); const DEMO_SPOOF_PATIENT_ID = 365881; var preventajaxcallendpoints = []; var preventajaxcallmessage = null; var iTopZIndex = 0; var w; var editingRecipeInPlace = ''; var editingExerciseInPlace = ''; function setDomainValues(domain) { subdomainCompanyName = domain.subdomain_company_name; subdomainLogoFile = domain.subdomain_logo_file; subdomainSplashFile = domain.subdomain_splash_file; subdomainFaviconFile = domain.subdomain_icon_file; subdomainCompanyTagLine = domain.subdomain_tag_line; subdomainCopyrightText = "© " + year + " " + domain.subdomain_copyright_text + " - All Rights Reserved
Rev "+versionNum+"
Technical Support"; PATIENT = domain.subdomain_patient_verbiage; } function clearJobStatus(json) { if( json['status'] == 1 ) { $("#job-status-" +json['job_id']).remove(); } } var lastX, timer; $(window).bind('touchmove', function(e) { clearTimeout(timer); var currentX = e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX; if (Math.abs(currentX-lastX) < 10) { return; } if (currentX> lastX) { } else { } lastX = currentX; timer = setTimeout(function() { last = 0; }, 500); }); dropup = function() { $(".dropdown-toggle").each(function() { par=$(this).parents('.btn-group'); dropl=par.find('ul'); otop=$(this).offset().top+$(this).height()-$(window).scrollTop(); ulh=dropl.height(); obot=$(window).height()-$(this).height()-$(this).offset().top+$(window).scrollTop(); if ((obot < ulh) && (otop > ulh)) { par.addClass('dropup'); } else { par.removeClass('dropup'); } }); } $(window).on('load', dropup); $(window).bind('resize scroll touchstart touchmove mousewheel', dropup); $(function() { if (window.location.hash && window.location.hash === "#_=_") { window.history.replaceState('', document.title, window.location.pathname); window.location.hash = ''; } document.addEventListener("touchstart", touchHandler, true); document.addEventListener("touchmove", touchHandler, true); document.addEventListener("touchend", touchHandler, true); document.addEventListener("touchcancel", touchHandler, true); if (document.location.search != '') { let uri = document.location.href; uri = uri.replace(document.location.search, ''); document.location.search = ''; document.location.href = uri; } $(document).on('click', '.pvbtn', function() { showPvbtnPanel($(this)); }); if(document.location.href === HOME_URI ) { $(window).on("resize",function() { resizeStuff(); }); $(document).on('click', '*[data-toggle="edit_input"]', function() { let editTarget = $(this).attr('data-target'); let editorID = ((editTarget.indexOf('#') == 0) ? editTarget.replace('#', '') : editTarget) + '-input'; let params = $(this).attr('data-params'); let jParams = JSON.parse(params); let editor = '
'; $(this).hide(); $(editTarget).hide().parent().prepend(editor); }); $(document).on('click', '*[data-toggle="edit_textarea"]', function() { let editTarget = $(this).attr('data-target'); let editorID = ((editTarget.indexOf('#') == 0) ? editTarget.replace('#', '') : editTarget) + '-textarea'; let params = ($(this).hasAttr('data-params')) ? $(this).attr('data-params') : ''; let jParams = (params !== '') ? JSON.parse(params) : []; let editTargetNodeType = $(editTarget).prop('nodeName'); let content = ''; let toolbars = ($(this).hasAttr('data-editor-toolbars')) ? JSON.parse($(this).attr('data-editor-toolbars')) : null; if ($(editTarget).find('.placeholder-text').length > 0) { content = ''; } else if (editTargetNodeType === 'DIV') { content = $(editTarget).html(); } else if (editTargetNodeType === 'INPUT') { content = $(editTarget).val(); } let saveBtn = ($(this).hasAttr('data-save-button') && $(this).attr('data-save-button') != '') ? false : true; let editor = ''; $(editTarget).hide().parent().append(editor); $(this).prop('disabled', true).addClass('disabled').hide(); $('#' + editorID).tinymce(saveBtn, null, false, toolbars); }); $('[data-bs-toggle="tooltip"]').tooltip({ trigger: 'hover' }); $(document).on('click', '.abtn', function(e) { objectClick( $(this) ); if ($(this).hasAttr('data-close-panel') && $(this).attr('data-close-panel') == 'true') { closePvbtnPanel($('.pvbtn-card').attr('id')); } $(this).blur(); e.preventDefault(); e.stopPropagation(); }); $(document).on('click', '*[data-toggle="input"]', function() { let targetInput = $(this).attr('data-target'); $(targetInput).click(); }); if (SERVER_NAME == 'www.mybodysite.com:88') { $('#watermark').html('QA'); } $(document).on('hidden.bs.modal', function() { if ($('.modal').hasClass('in') == false) { $('body').removeClass('modal-open'); $('.modal-backdrop').remove(); } }); $(document).on('shown.bs.modal', function (e) { if ($('body.modal-open').length == 0) { $('body').addClass('modal-open'); } let modal = $(e.target); if (modal.find('input:first').attr('data-toggle') != 'datepicker') { modal.find('input:first').trigger('focus'); } let bodyHeight = getModalBodyHeight(modal); modal.find('.modal-body').css('max-height', bodyHeight).css('overflow-y', 'auto'); if (!$('.modal-backdrop').length) { $('body').append(''); } }); $(document).on('show.bs.tab', '.nav-menu-item', function () { let tab = $(this); tab.find('.nav-menu-item-badge').remove(); if (tab.hasAttr('data-background-class')) { $('body').addClass(tab.attr('data-background-class')); } else { $('body').removeClass(function (index, className) { return ((BACKGROUND_CLASSES.indexOf(className) != -1) ? className : ''); }); } if (tab.hasAttr('data-script') && tab.hasAttr('data-function')) { const script = tab.attr('data-script'); const callbackFn = tab.attr('data-function'); const tabID = tab.attr('data-target'); loadScript(script, function() { window[callbackFn](tabID); initOutput(); }); } if (tab.hasAttr('data-session-timeout') && tab.attr('data-session-timeout') === 'false') { // we shouldn't time the user out while they're on this tab if (window.sessMon !== undefined && window.sessMon.pingAction === 'click') { window.sessMon.switchToTimer(); } } else { // time them out after inactivity if (window.sessMon !== undefined && window.sessMon.pingAction === 'timer') { window.sessMon.switchToClick(); } } // nav menu tabs triggered from a dropdown no longer behave as expected in Bootstrap 5 // this is a workaround to correct that const tabPaneID = tab.attr('href'); $('.main-section').removeClass('active'); $(tabPaneID).addClass('active'); }); $(document).on('click', '.print-btn', function() { window.print(); }); $(document).on('click', '.dropdown-item', function() { $(this).parent().find('.dropdown-item.active').removeClass('active'); $(this).addClass('active'); if ($(this).hasClass('abtn') == false) { $(this).parent().removeClass('show'); } }); $(document).on('shown.bs.dropdown', '.dropdown, .dropstart', function(e) { $(this).find('.dropdown-item.active').removeClass('active'); }); $(document).on('click', 'li.breadcrumb-item > a', function() { let bar = $(this).parent().parent(); // get current active item let currentItem = bar.find('.breadcrumb-item.active'); // remove active and hide the target currentItem.removeClass('active'); $(currentItem.attr('data-target')).hide(); // show the new item and make it active $($(this).attr('data-target')).show(); $(this).parent().addClass('active').removeClass('text-info'); // if this is NOT the last item, remove all the items after it if (bar.last().find('a') != $(this)) { $(this).parent().nextAll('li').each(function() { $($(this).find('a').attr('data-target')).hide(); $(this).remove(); }); } // if we only have one item left now, remove the bar itself if (bar.find('li').length == 1) { bar.remove(); } // if we have an endpoint, do the ajax call if ($(this).hasAttr('data-endpoint')) { executeAjaxCall($(this)); } }); // get user 'Home' screen $.ajax({ url:AJAXURI+'/home/', method:"POST", dataType:"JSON", headers: { 'X-CSRF-Token': Math.random().toString(20).substr(2, 20) }, success:function( json ) { if (json.status === 1) { setDomainValues(json.domain_info); accountType = json.account_type; if (typeof(sessionMonitor) != 'undefined') { sessMon = sessionMonitor({ sessionLifetime: MAX_SESSION_LENGTH * 1000, timeBeforeWarning: TIMEOUT_WARNING_LENGTH * 1000 }); window.sessMon = sessMon; } parseJSONresponse(json, 'body'); } else { // failed, we might not be logged in window.Appcues.reset(); loginForm(); } } }); resizeStuff(); } }); function getModalBodyHeight(modal) { let headerHeight = modal.find('.modal-header').height(); let footerHeight = (modal.find('.modal-footer').length > 0) ? modal.find('.modal-footer').height() : 0; let perc = (footerHeight > 0) ? .8 : .85; let maxHeight = window.innerHeight * perc; let bodyHeight = maxHeight - (headerHeight + footerHeight); return bodyHeight; } function showPvbtnPanel(btn) { var custom_modal_id = 'preview_' + generateUUID(); let bodyID = custom_modal_id + '_body'; var html = ''; const maxWidth = $(window).width() * .95; var iMaxWidth = (btn.attr("data-max-width")) ? btn.attr("data-max-width") : maxWidth + 'px'; if (iMaxWidth.indexOf('%') != -1) { var iPercent = Number(iMaxWidth.replace('%', '')) / 100; if (($("#tabs").width() * iPercent) < 472) { iMaxWidth = $("#tabs").width() + 'px'; } } var iMaxHeight = (btn.attr("data-max-height")) ? btn.attr("data-max-height") : $(window).height() - 40 + 'px'; var iBodyHeight = (btn.attr("data-max-height")) ? btn.attr("data-max-height") : $(window).height() - 100 + 'px'; var showWatermark = (btn.hasAttr('data-show-watermark')) ? btn.attr('data-show-watermark') : 'false' html += '
'; html += ''; html += '
'; html += '
'; btn.attr("data-replace-dom", bodyID); if ($('.pvbtn-card').length > 0) { $('.pvbtn-card').hide(); } $("#mainbody").append(html); $("#mainbody div.row:first").hide(); $('body').append(''); $("#close-preview-pane_" + custom_modal_id).off().on("click", function () { closePvbtnPanel(custom_modal_id); }); $("#" + custom_modal_id).appendTo('body').center(); if (btn.hasAttr('data-endpoint')) { executeAjaxCall(btn); } scrollTo(0, 0); return bodyID; } function closePvbtnPanel(id) { $("#" + id).remove(); $('.modal-backdrop').remove(); $("#mainbody div.row:first").show(); if ($('.pvbtn-card').length > 0) { $('.pvbtn-card').show(); } else { $('.navbar').css('width', ''); } } jQuery.fn.removeModal = function(removeFromDOM) { removeFromDOM = (undefined !== removeFromDOM) ? removeFromDOM : false; $(this).modal('hide'); $('body').removeClass('modal-open'); $('.modal-backdrop').remove(); if (removeFromDOM) { $(this).remove(); } }; jQuery.fn.addBreadcrumb = function(options) { $(this).find('.refresh-breadcrumb-item').remove(); $(this).find('.breadcrumb-item.active').removeClass('active').addClass('text-info'); let endpoint = (options.hasOwnProperty('endpoint')) ? 'data-endpoint="' + options.endpoint + '"' : ''; let params = (options.hasOwnProperty('params')) ? 'data-params="' + prepareJSONparams(options.params) + '"' : ''; let replacedom = (options.hasOwnProperty('replacedom')) ? 'data-replace-dom="' + options.replacedom + '"' : ''; let showWaiter = (options.hasOwnProperty('show_waiter')) ? 'data-show-waiter="' + options.show_waiter + '"' : ''; let breadcrumbHtml = ''); if (!options.hasOwnProperty('refresh_btn') || (options.hasOwnProperty('refresh_btn') && options.refresh_btn === true)) { breadcrumbHtml += '  '; } breadcrumbHtml += ''; $(this).append(breadcrumbHtml); } jQuery.fn.removeLastBreadcrumb = function() { $(this).find('li:last').remove(); } // JSON response from ajax call comes here function parseJSONresponse(json, replacedom, supressMessage) { supressMessage = (undefined == supressMessage) ? false : supressMessage; if( json != null ) { if( ( json['status'] == -1 || json['status'] == 1 ) && json.hasOwnProperty('location') ) { // -1 == bail out document.location.href = json['location']; return false; } if (json['status'] == 1 && json.hasOwnProperty('new_window')) { window.open(json['new_window'],'_blank'); return; } // process any JSON and 'message' values if(!supressMessage) { if (json.hasOwnProperty('status') && json.hasOwnProperty('message')) { jsonResponseMessage(json); } else if (json.hasOwnProperty('status') && json.status == 0 && (json.hasOwnProperty('modal_message') || json.hasOwnProperty('lg_modal_message'))) { let modalSize = (json.hasOwnProperty('lg_modal_message')) ? 'lg' : null; renderErrorModal(json, modalSize); } } if( json.hasOwnProperty('endpoint') ) { var endpoint = json['endpoint']; if (endpoint === '/logout_attempt/') { if (json['status'] == 1) { document.location.href = document.location.origin; } } let callbackProcessed = callbackProcessor({ endpoint: endpoint, json: json, replacedom: replacedom }); if (!callbackProcessed.executed) { if (endpoint === '/home/') { if (json.hasOwnProperty('menu')) { var jMenu = json['menu']; var menuhtml = buildNavMenuTabs(jMenu); $("#main").html(menuhtml); if (json.hasOwnProperty('announcements')) { renderAnnouncement(json['announcements']); } } if (json.timezone == null) { // set the timezone in the database let endpoint = '/update_user_timezone/'; let params = {}; params.endpoint = endpoint; params.params = {}; params.params.timezone_id = Intl.DateTimeFormat().resolvedOptions().timeZone; ajaxCall(endpoint, params, null); } if (json.account_type === 'P' || json.account_type === 'S') { window.Appcues.identify( json.user_id, { role: json.account_type } ); } if (window.hasOwnProperty('newrelic') && window.newrelic !== undefined) { window.newrelic.setUserId(json.user_id.toString()); } // if we have a predetermined destination, don't autoload anything if (sessionStorage.getItem('destination')) { $(".section-autoload").removeClass("section-autoload"); } // init nav tabs if (initOutput()) { // when we're actually done init-ing the nav tabs, THEN process our direct link stuff if (sessionStorage.getItem('destination')) { let params = sessionStorage.getItem('destination'); sessionStorage.clear(); $.getScript(scriptbase + 'direct_link.js', function () { processDirectLink(params); }); } if (json.hasOwnProperty('needs_baa') && json.needs_baa === true) { if (json.account_type === 'P' && json.hasOwnProperty('is_domain_admin') && json.is_domain_admin === true) { // this is the user that needs to sign the BAA ajaxCall('/provider_get_baa/', [], function(json) { if (json.status === 1) { renderBAAForSignature(json); } }, true); } else { ajaxCall('/nag_domain_admin_about_baa/', [], function(json) { renderBBABlockerModalForNonDomainAdmin(json); }); } } } } else if (endpoint === '/account_settings/') { var replacedomArr = replacedom.split('-'); replacedom = replacedomArr[0]; var innerCallbackFunction = function (replacedomArrPart2) { var theMyTeamSettingInterval = setInterval(function () { const teamTab = $('#' + replacedomArrPart2); if (teamTab.length === 1) { clearInterval(theMyTeamSettingInterval); const settingsBsTab = new bootstrap.Tab('#mainnavul a.nav-link[href="#settings"]'); settingsBsTab.show(); const teamBsTab = new bootstrap.Tab(teamTab); teamBsTab.show(); objectClick(teamTab); } }, 5); } $.getScript(scriptbase + "account.js", function () { // accountLoaded = 1; renderAccountSettings(json, replacedom); $('a.nav-menu-item[data-endpoint="/account_settings/"]').tab('show'); if (replacedomArr.length === 2) { innerCallbackFunction(replacedomArr[1]); } }); } else if (endpoint === '/domain_admin_toggle_private_messaging/' || endpoint === '/domain_admin_toggle_virtual_clinic/') { if (json['status'] === 1) { setTimeout(function () { document.location.href = document.location.origin; }, 1500); } } else if (endpoint === '/upload_photo/') { if ($('#' + replacedom).hasAttr('data-uuid')) { $.getScript(scriptbase + 'content_libraries.js', function () { renderContentLibraryPhotoAlbum(json, replacedom); }); } else { $.getScript(scriptbase + "photos.js", function () { // photosLoaded = 1; updatePhotoAlbum(json, replacedom); }); } } else if (endpoint === '/clear_job/') { clearJobStatus(json); } else if (endpoint === '/patient_staff_messages/') { if (json['status'] == 0) { $("#mainnavul li").find("[href='#messages']").remove(); $("#messages").remove(); } else { $.getScript(scriptbase + "messages.js", function () { // messagesLoaded = 1; renderStaffMessages(json, replacedom); }); } } else if (endpoint === '/messages/') { if (json['status'] == 0) { $("#mainnavul li").find("[href='#messages']").remove(); $("#messages").remove(); } else { $.getScript(scriptbase + "messages.js", function () { // messagesLoaded = 1; renderMessages(json, replacedom); }); } } else if (endpoint === '/program/') { loadScript('plans.js', function () { loadScript('program.js', function () { Program.renderProgram(json, replacedom); if (json.redirectToPage !== undefined) { if ($('a[href^="#' + json.redirectToPage + '"]').length > 0) { $('a[href^="#' + json.redirectToPage + '"]').trigger('click'); } } }); }); } else if (endpoint === '/provider_edit_meal/' || endpoint === '/provider_update_meal_food_serving_count/' || endpoint === '/provider_remove_meal_food_item/' || endpoint === '/provider_add_food_to_meal/') { $.getScript(scriptbase + "meals.js", function () { // mealsLoaded = 1; if (endpoint === '/provider_update_meal_food_serving_count/' || endpoint === '/provider_remove_meal_food_item/' || endpoint === '/provider_add_food_to_meal/') { document.cookie = "dirty_recipe_editor=true"; $('#done-editing-recipe-btn').removeClass('btn-secondary').addClass('btn-primary').prop('disabled', false); } renderProviderEditRecipe(json, replacedom); }); } else if (endpoint === '/send_private_message/' || endpoint === '/send_private_message_to_staff/') { if (accountType == 'P' || accountType == 'S') { if ($('.compose-message-modal').hasClass('show')) { $('.compose-message-modal').removeModal(); } if (replacedom == 'messages') { $.getScript(scriptbase + 'messages.js', function () { renderProviderMessages(json, replacedom); }); } else if (replacedom == 'conversation-detail') { $.getScript(scriptbase + 'messages.js', function () { renderMessageConversation(json, replacedom); }); } else if (replacedom == 'patient-detail-messages') { $.getScript(scriptbase + 'patient_detail.js', function () { sendPatientMessageCallback(json, replacedom); }); } } else { $.getScript(scriptbase + "messages.js", function () { newProviderMessageCallback(json); }); } } else if (endpoint == '/provider_check_baa_signature_status/') { checkContractSignedCallback(json, replacedom); } else if (endpoint === '/provider_opt_out_of_baa/') { optOutOfBAACallback(json); } else if (endpoint === '/save_survey_answer/') { loadScript('surveys.js', function () { answerQuestionCallback(json); }); loadScript("patients.js", function () { updateSurveyStartDate(json); }); } else if (endpoint === '/finish_survey/') { loadScript('surveys.js', function () { finishSurveyCallback(json); }); if (accountType === 'P' || accountType === 'S') { loadScript("patient_detail.js", function () { renderManagePatientSurveys(json, replacedom); }); } else if (accountType === 'U') { loadScript("program.js", function () { Program.finishSurveyCallback(json, replacedom); }); } } else if (endpoint === "/admin_update_transaction_email/") { if ( parseInt( json['status'] ) === 1 ) $('#'+replacedom).html( json['data']['email'] ).prev('td').find('.updateBuyerPatientEmail').data('email', json['data']['email']); } else if (endpoint === '/set_user_calorie_goal/') { if (accountType === 'U') { loadScript('food.js', function () { renderSetCalorieGoalCallback(json); }); } else if (accountType === 'P') { loadScript('patients.js', function () { updateCalorieGoalCallback(json); }); } } else if (endpoint === '/get_bonus_tab_content/') { let tabID = json['data']['tab_id']; if (replacedom === 'edit-plan-bonus-tab-content-' + tabID) { // rendering tab content when editing a plan requires a different rendering function loadScript('edit_plan.js', function () { renderEditPlanBonusTabContent(json, replacedom); }); } else { loadScript('program.js', function () { Program.renderProgramBonusTabContent(json, replacedom); }); } } else if (endpoint === '/update_custom_food_serving/') { loadScript('food.js', function () { renderUpdateCustomFoodServing(json, replacedom); }); if (accountType === 'P') { loadScript('meals.js', function () { renderUpdateCustomFoodList(json); }); } } else if (endpoint === '/add_custom_food_serving/') { loadScript('food.js', function () { renderNewServingAdded(json, replacedom); }); if (accountType === 'P') { loadScript('meals.js', function () { renderUpdateCustomFoodList(json); }); } } else if (endpoint === '/update_custom_food/') { if (accountType === 'P') { loadScript('meals.js', function () { renderUpdateCustomFoodList(json); }); } } else if (endpoint === '/update_custom_food_photo/') { if (accountType === 'P') { loadScript('meals.js', function () { renderUpdateCustomFoodList(json); }); } } else if (endpoint === '/preview_plan_day_as_email/') { if (json.status == 1) { $('#' + replacedom).removeModal(); } } else if (endpoint === '/provider_edit_recipe_in_place/') { loadScript('meals.js', function () { editingRecipeInPlace = replacedom; renderProviderEditRecipe(json, replacedom); }); } else if (endpoint === '/provider_edit_exercise_in_place/') { loadScript('exercises.js', function () { editingExerciseInPlace = replacedom; renderExerciseEditor(json, replacedom); }); } else if (endpoint === '/provider_update_inbody_api_credentials/') { if (accountType == 'P') { loadScript('account.js', function () { renderInbodyAPIAccessCallback(json, replacedom); }); } } else if (endpoint === '/provider_resell_premium_plan/' || endpoint === '/provider_sell_exclusive_plan/') { loadScript('plans.js', function () { if ($('div.modal.show').length > 0) { $('div.modal.show').removeModal(); } renderEditPlan(json, replacedom); }); } else if (endpoint === '/upload_photo_tinymce/') { $.getScript(HTTP_PATH + '/image_browser/image_browser.js', function () { managePhotoAlbumImageBrowser(json, replacedom); }); } } } } } function renderErrorModal(json, modalSize, showHeader) { modalSize = (undefined === modalSize) ? null : modalSize; showHeader = (undefined === showHeader) ? true : showHeader; let html = ''; let modalID = 'error-message-' + generateUUID(); const message = (json.hasOwnProperty('modal_message')) ? json.modal_message : json.lg_modal_message; html += `'; // modal $('body').append(html); if ($('div.modal.show').length) { // if there is a modal showing currently, // we should hide it so we can show the timeout warning // and then show it again if the user chooses to stay logged in let currentModalID = $('div.modal.show').attr('id'); $('#' + currentModalID).modal('hide'); } $('#' + modalID).modal({ backdrop: 'static' }).modal('show'); } function jsonResponseMessage( json ) { // check for ajax message box, add to DOM if necessary if($(".ajax-message").length == 0) { if( ismobile ) $("body").append('
'); else $("#mainnavbar").parent().prepend('
'); } if ($('.pvbtn-card').length > 0 && $('.pvbtn-card-ajax-message').length == 0) { $('.previewmain').prepend('
'); } else if ($('.modal-dialog').length > 0 && $('.modal-dialog-ajax-message').length == 0 && $('.modal-dialog').is(':visible')) { $('.modal-body:visible').prepend(''); } var alertClass = ''; var sMsgHtml = ''; if( json['status'] == 1 && json.hasOwnProperty('message') ) { // Success alertClass = 'alert-success'; } if( json['status'] == 2 && json.hasOwnProperty('message') ) { alertClass = 'alert-info'; } if( json['status'] == 0 && json.hasOwnProperty('message') ) { // Something went wrong or didn't save/update AND we have a message to display to the user alertClass = 'alert-warning'; // If we have an action called reset if( json.hasOwnProperty('action') && json['action'] == 'reset' ) { // Clear the page and show an alert box (such as maybe their session timed out) $(".ajax-message").empty(); if ($('.pvbtn-card').length > 0) { $('.pvbtn-card').empty().remove(); } $("#mainbody").empty().html('
' + nl2br( json['message'] ) + '
'); $("#reset").unbind().bind("click",function() { // Page refresh $(window).unbind('beforeunload'); document.location.href = document.location.origin; }); return false; } } sMsgHtml = '
' + nl2br(json['message']) + '
'; if ($('.pvbtn-card-ajax-message').length > 0) { $('.pvbtn-card-ajax-message').html(sMsgHtml); $(".pvbtn-card-ajax-message").css({"position":"fixed","top":"0.5em","margin":"auto","width": ($("#mainbody").width() * 0.90 ) +"px"}).show().zIndex(iVeryTop()); } else if ($('.modal-dialog-ajax-message').length > 0) { $('.modal-dialog-ajax-message').html(sMsgHtml); $(".modal-dialog-ajax-message").css({"position":"fixed","top":"0.5em","margin":"auto","width": ($(".modal-dialog-ajax-message").parent().width() * 0.90 ) +"px"}).show().zIndex(iVeryTop()); } else { $(".ajax-message").html(sMsgHtml); } // If dismiss button isn't clicked, automatically remove the pop-up dialog after this timeout setTimeout(function(){$(".ajax-message").empty().hide();},5000); if( ismobile == true ) { $(".ajax-message").css({"position":"fixed","bottom":"0","margin":"auto","width": ($("#mainbody").width() * 0.90 ) +"px"}).show().zIndex(MAX_Z_INDEX); } else { $(".ajax-message").css({"position":"fixed","top":"0.5em","margin":"auto","width": ($("#mainbody").width() * 0.90 ) +"px"}).show().zIndex(MAX_Z_INDEX); } } function initOutput() { setTimeout(function() { $(".admin-report-table tbody .admin-report-cell").bind("mouseover",function(){$(this).addClass("mark")}) .bind("mouseout",function(){$(this).removeClass("mark");}); },500); // when showing modals $(window).on('shown.bs.modal', function() { $("[data-spy='affix']").each(function(e) { $(this).attr("data-z-index", $(this).zIndex() ).zIndex(500); }); }); // when hiding modals $(window).on('hidden.bs.modal', function() { $("[data-spy='affix']").each(function(e) { $(this).zIndex( $(this).attr("data-z-index") ).attr("data-z-index","") }); }); // dropdown menus don't always go away after clicking an item, so if we have any hanging around get rid of them if ($('.dropdown-menu.show').length > 0) { $('.dropdown-menu.show').removeClass('show'); } // if any items are still highlighted, un-highlight them if ($('.dropdown-item.active').length > 0) { $('.dropdown-item.active').removeClass('active'); } $('.table-responsive').on('show.bs.dropdown', function () { $('.table-responsive').css("overflow", "inherit"); }); $('.table-responsive').on('hide.bs.dropdown', function () { $('.table-responsive').css("overflow", "auto"); }) $(".nav-jump").bind("click", function (e) { var domid = $(this).attr("data-target"); setTimeout(function () { $('html,body').animate({ scrollTop: $('#' + domid).offset().top }); }, 50); }); if ($("[data-toggle='toggle']").length > 0) { $("input[data-toggle='toggle']").bootstrapToggle(); $("input[data-toggle='toggle']").each(function () { if (undefined !== $(this).attr("data-endpoint") && undefined !== $(this).attr("data-params")) { // if it has an endpoint, unbind first so that we don't end up hitting the same endpoint multiple times $(this).off().on('change', function (e) { var params = JSON.parse($(this).attr("data-params")); for (i in params) { if (params[i]['name'] == 'checked') { params[i]['value'] = $(this).prop("checked"); } } $(this).attr("data-params", JSON.stringify(params)); objectClick($(this)); }); } }); } if ($(".pull-down").length > 0) { $(".pull-down").each(function () { var thisH = $(this).height(); var parentH = $(this).parent().height(); $(this).parent().css({ "padding-top": thisH + "px" }); }); } if ($("input[type='number']").length > 0) { $("input[type='number']").on("change", function () { if ($(this).val() < 0) { $(this).val($(this).val() * (-1)); } }); } // initialize trash icon buttons with ".trash-clear-icon" if ($(".trash-clear-icon").length > 0) { $('.trash-clear-icon').attr('data-toggle', 'tooltip').attr('data-title', 'Clear Entry').html(''); $(".trash-clear-icon").on("click", function () { var input = $(this).attr("data-clear-dom"); $("#" + input).val('').focus(); $(this).blur(); }); } // when a tab/pill navigation link is clicked, if its corresponding div is empty, load its initial state $('a[data-bs-toggle="tab"]').off().on("click", function () { const tabMenuItem = $(this); if (tabMenuItem.hasAttr('data-endpoint')) { $("#mainnavbar").collapse('hide'); $("#ajax-message").empty(); let allowRefresh = tabMenuItem.hasAttr('data-allow-refresh') ? tabMenuItem.attr('data-allow-refresh') : false; allowRefresh = JSON.parse(allowRefresh); // parses string to bool const sectionID = (undefined !== tabMenuItem.attr("data-replace-dom")) ? tabMenuItem.attr("data-replace-dom") : tabMenuItem.attr("href").replace("#", ""); const section = $('#' + sectionID); if ((section.length > 0 && section.html() === '') || allowRefresh) { objectClick(tabMenuItem); } } }); $('#mainnavul > li.nav-item > .nav-menu-item.active').off().on('click', function() { objectClick($(this)); }); // initialize any DOM inputs with css class/selector 'ainput' listening for the 'Enter' keypress to submit/execute if ($(".ainput").length > 0) { $(".ainput").unbind().bind("keyup", function (e) { if (e.which == 13) // keycode 13 is 'Enter' key { objectClick($(this)); $(this).blur(); } }); } if ($('.adrop').length > 0) { $('.adrop').on('drop', function (event) { event.preventDefault(); event.stopPropagation(); objectClick($(this)); $(this).blur(); }); } if ($(".section-autoload").length > 0) { // if there are any sections marked as 'autoload', load them $(".section-autoload").each(function () { var section = $(this).attr("id"); $("#mainnavbar").find("a[href='#" + section + "']").addClass("active"); }); objectClick($(".section-autoload")); $(".section-autoload").removeClass("section-autoload"); } $("#toggle_width").unbind().bind("click", function () { $(".container-fluid, .container").toggleClass("container-fluid container"); }); resizeStuff(); if ($('*[data-bs-toggle="tooltip"]').length > 0) { setTimeout(function () { $('*[data-bs-toggle="tooltip"]').tooltip({ placement: 'auto', trigger: 'hover' }); }, 500); // sometimes a tooltip object stays on the dom for whatever reason, so if we have a lingering open tooltip, remove it. if ($('.tooltip.show').length > 0) { $('.tooltip.show').remove(); } } // initialize any "list filter" DOM objects if ($(".list-filter").length > 0) { $(".list-filter").each(function () { var filterlist = $(this).attr("data-filter-against"); $(this).unbind().bind("keyup", function () { var term = $(this).val().toLowerCase(); var items = $("#" + filterlist).find("a"); items.each(function () { if ($(this).text().toLowerCase().match(term)) { $(this).show(); } else { $(this).hide(); } }); }); }); } if ($("[data-bs-toggle='popover']").length > 0) { $("[data-bs-toggle='popover']").popover(); } // sometimes safari on iOS decides a isn't clickable, so now all the glyphicons have a dummy click even that does nothing $('.glyphicon').on('click', function () { void(0); }); $('.fa').on('click', function () { void(0); }); $('*[data-toggle="datepicker"]').each(function() { if ($(this).hasClass('datepicker-initialized') == false) { $(this).createDatePicker(); } }); $('[data-bs-toggle="collapse"]').on('click', function () { if ($(this).find('.fa-angle-down').length > 0) { $(this).find('.fa-angle-down').removeClass('fa-angle-down').addClass('fa-angle-up'); } else if ($(this).find('.fa-angle-up').length > 0) { $(this).find('.fa-angle-up').removeClass('fa-angle-up').addClass('fa-angle-down'); } }); $('.collapse').on('show.bs.collapse', function () { let header = $(this).parent().find('.card-header[data-bs-toggle="collapse"]'); if (header.find('.fa-angle-down').length > 0) { header.find('.fa-angle-down').removeClass('fa-angle-down').addClass('fa-angle-up'); } }).on('hide.bs.collapse', function() { let header = $(this).parent().find('.card-header[data-bs-toggle="collapse"]'); if (header.find('.fa-angle-up').length > 0) { header.find('.fa-angle-up').removeClass('fa-angle-up').addClass('fa-angle-down'); } }); $('a[data-toggle="nav-menu-item"]').on('click', function(e) { let endpoint = $(this).attr('data-nav-item-endpoint'); $('#mainnavul').find('li.active').removeClass('active'); $('.main-section.active').removeClass('active'); goToNavItem(endpoint); }); let scrollCall = function() { let hitBottom = $(this).hasAttr('data-scrolled-to-bottom') ? parseInt($(this).attr('data-scrolled-to-bottom')) : 0; if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight * .75) { if (hitBottom == 0) { $(this).attr('data-scrolled-to-bottom', '1'); // do ajax call objectClick($(this)); } } }; if (typeof _ !== 'undefined') { $('.ascroll').on('scroll', _.throttle(scrollCall, 500)); } $('.modal-header').each(function() { if ($(this).children('.btn-close').length === 0 && !$(this).hasClass('no-close-btn')) { $(this).append(closeModal()); } }); return true; } // Runs when "abtn" clicked or activated by 'Enter' on inputs with 'ainput' css selector/class function objectClick( thisObject ) { $("#ajax-message").empty(); if (thisObject.hasClass('nav-menu-item') || thisObject.hasClass('main-section')) { if (thisObject.hasAttr('data-background-class')) { $('body').addClass(thisObject.attr('data-background-class')); } else { $('body').removeClass(function(index, className) { return ((BACKGROUND_CLASSES.indexOf(className) != -1) ? className : ''); }); } } if( thisObject.attr("data-action-prompt-message") ) { if ($('#confirmmodal').length > 0) { $('#confirmmodal').removeModal(true); } var confirmmodal = ''; confirmmodal += ''; $("body").append(confirmmodal); const confirmBsModal = new bootstrap.Modal('#confirmmodal', { backdrop: 'static', keyboard: false }); confirmBsModal.show(); // 'No' button clicked $(".cancel-modal-action").on("click",function() { if( thisObject.is("input[type='checkbox']") && thisObject.attr("data-toggle") == "toggle" ) { if( thisObject.prop("checked") == true ) { thisObject.prop("checked",false ); thisObject.bootstrapToggle('off'); } else { thisObject.bootstrapToggle('on'); thisObject.prop("checked",true ); } } }); // 'Yes' button clicked $("#confirm-modal-action").on("click",function() { let doCall = true; if (thisObject.attr('data-endpoint') === '/logout_attempt/' && undefined !== window.rpmMonitor) { if (window.rpmMonitor.timer_running) { doCall = false; window.rpmMonitor.stopTimer(function() { executeAjaxCall( thisObject ); }); } } if (doCall) { preventajaxcallendpoints = []; preventajaxcallmessage = null; executeAjaxCall(thisObject); $("#confirmmodal").empty().remove(); } }); } else // no action-prompt { executeAjaxCall( thisObject ); } } function ajaxCall(endpoint, params, successcallback, showWaiter, btnObject) { let postparams = encodeURIComponent( JSON.stringify(params) ); let csrfToken = Math.random().toString(20).substr(2, 20); // TODO: replace with real token showWaiter = (typeof showWaiter === 'boolean') ? showWaiter : false; successcallback = (typeof successcallback === 'function') ? successcallback : function(json) { /* do nothing */}; setTimeout(function() { // empty the ajax-message box $.ajax({ url:AJAXURI + endpoint, method: "POST", dataType: 'JSON', data: { 'data':postparams }, headers: { 'X-CSRF-Token': csrfToken }, beforeSend: function(xhr) { if (showWaiter) { showWaitSpinner(); } if (typeof btnObject !== 'undefined') { btnObject.append(''); } }, success:function(json, status, xhr) { hideWaitSpinner(); $('#button-waiter').remove(); successcallback(json); }, error:function(xhr, status, error) { // Do error stuff here hideWaitSpinner(); $('#button-waiter').remove(); jsonResponseMessage({ status: 0, message: "Something went wrong, please try again." }); console.log('AJAX request failed: '+error); }, complete: function(xhr, status) { if ($('#pleasewait').length > 0) { hideWaitSpinner(); } } }); }, 50); } // Execute the ajax call on a DOM object and run the standard 'parseJSONResponse' callback // or the given callback function executeAjaxCall( thisObject, callCallbackFunction ) { var params = {}; var endpoint = thisObject.attr("data-endpoint"); if( preventajaxcallendpoints.length > 0 ) { if( preventajaxcallendpoints.indexOf(endpoint) != -1 ) { preventExecuteAjaxModal( thisObject ); return false; } } var replacedom = thisObject.attr("data-replace-dom"); // Place in the DOM where new data will be rendered params['endpoint'] = endpoint; let showWaiter = (thisObject.hasAttr('data-show-waiter') && thisObject.attr('data-show-waiter') == 'true') ? true : false; let supressMessage = (thisObject.hasAttr('data-supress-message') && thisObject.attr('data-supress-message') == 'true') ? true : false; let callbackFn = (thisObject.hasAttr('data-callbackfn') && thisObject.attr('data-callbackfn') != '') ? thisObject.attr('data-callbackfn') : null; let adminEndpoint = endpoint.indexOf('admin'); let libraryEndpoint = endpoint.indexOf('library'); if (adminEndpoint != -1 || libraryEndpoint != -1) { showWaiter = true; } if( thisObject.attr("data-params") ) { let buttonparams = JSON.parse( thisObject.attr("data-params") ); if( buttonparams.length > 0 ) { params['params'] = {}; for(let n = 0; n < buttonparams.length; n++) { let thisparamname = buttonparams[n]['name']; let thisparamvalue = ''; if( buttonparams[n].hasOwnProperty('value') ) { // element has set value thisparamvalue = buttonparams[n]['value']; } else if( buttonparams[n].hasOwnProperty('html_of') ) { // Obtain value from tinyMCE editor, identified by the "html_of" identifier thisparamvalue = tinymce.get(buttonparams[n]['html_of']).getContent(); } else if( buttonparams[n].hasOwnProperty('value_of') ) { let identifier = buttonparams[n]['value_of']; let thisInput = $('#' + identifier); if (thisInput.length > 0) { // Obtain value from DOM object, identified by the "value_of" identifier thisparamvalue = thisInput.val(); } else if ($('*[name="' + identifier + '"]').length > 0 && $('*[name="' + identifier + '"]').is('input[type="radio"]')) { // get the selected radio button thisparamvalue = getSelectedRadioVal($('*[name="' + identifier + '"]')); } } else if( buttonparams[n].hasOwnProperty('value_get') ) { if( buttonparams[n]['value_get'] == 'imei' ) thisparamvalue = $("#uuid").val(); else if( buttonparams[n]['value_get'] == 'local_date' ) thisparamvalue = getTodayDateForServer(); } else if ( buttonparams[n].hasOwnProperty('value_of_attribute')) { // get value of custom attribute in specified DOM object thisparamvalue = $('#'+buttonparams[n]['value_of_attribute']).attr('custom_attribute_value'); } else if (buttonparams[n].hasOwnProperty('is_checked')) { // get state of given checkbox let cb = $("#" + buttonparams[n]['is_checked']); thisparamvalue = cb.prop('checked'); } params['params'][thisparamname] = thisparamvalue; } } } // Escape stuff so it passes OK over http var postparams = encodeURIComponent( JSON.stringify(params) ); setTimeout(function() { // empty the ajax-message box $.ajax({ url:AJAXURI + endpoint, method:"POST", dataType:'JSON', data:{ 'data':postparams }, headers: { 'X-CSRF-Token': Math.random().toString(20).substr(2, 20) }, beforeSend: function(xhr) { if (showWaiter) { showWaitSpinner(); } else { if (thisObject.is('button') || thisObject.is('.dropdown-item')) { thisObject.append(''); } } }, success:function(json, status, xhr) { $('#button-waiter').remove(); hideWaitSpinner(); // Results of ajax post come here // json - my json string of data // replacedom - location in the DOM where the new data will be rendered if (typeof callCallbackFunction == 'function') { callCallbackFunction(json, replacedom); } else { parseJSONresponse(json, replacedom, supressMessage); } }, error:function(xhr, status, error) { // Do error stuff here $('#button-waiter').remove(); hideWaitSpinner(); jsonResponseMessage({ status: 0, message: "Something went wrong, please try again." }); console.log('AJAX request failed: '+error); } }); },50); } function showWaitSpinner() { $("#pleasewait").html('
').height($(window).height()).css({ "left": "0", "top": "0", "z-index": MAX_Z_INDEX }).show(); } function hideWaitSpinner() { $("#pleasewait").empty().hide(); } // // function preventExecuteAjaxModal( object ) { var confirmmodal = ''; var confirmmodalid = 'confirm-modal-'+generateUUID(); confirmmodal += ''; $("body").append( confirmmodal ); $("#"+confirmmodalid).modal().on('hidden.bs.modal', function () {$("#"+confirmmodalid).remove();}); $("#confirm-continue-endpoint").unbind().bind("click",function() { preventajaxcallendpoints = []; preventajaxcallmessage = null; executeAjaxCall( object ); }); } function buildNavMenuTabs( jMenu ) { var html = ''; html += ''; // tabbed content html += '
'; html += '
'; html += '
'; html += '
'; for(let n in jMenu) { var item = jMenu[n]; if( item.length === 1 && item[0]['type'] === 'section') { let replaceDom = item[0]['label'].replace(/\s|\+|\/|'/g, "_").toLowerCase(); var thisParams = ( item[0].hasOwnProperty('params') ) ? 'data-params="'+JSON.stringify(item[0]['params']).replace(/'/g,"'").replace(/"/g,""")+'" ' : ''; let bgClass = item[0].hasOwnProperty('background') ? 'data-background-class="' + item[0]['background'] + '"' : ''; if( undefined !== item[0]['default'] && item[0]['default'] == true ) // load this section on DOM READ { html += '
'; } else html += '
'; } else if (item.length > 1 ) { for(let i in item) { if(i > 0 && item[i]['type'] === 'section' || i > 0 && item[i]['type'] === 'tab') { let replaceDom = item[i]['label'].replace(/\s|\//g, "_").toLowerCase(); let bgClass = item[0].hasOwnProperty('background') ? 'data-background-class="' + item[0]['background'] + '"' : ''; var thisParams = ( item[i].hasOwnProperty('params') ) ? 'data-params="'+JSON.stringify(item[i]['params']).replace(/'/g,"'").replace(/"/g,""")+'" ' : ''; if( undefined !== item[i]['default'] && item[i]['default'] == true ) // load this section on DOM READ { html += '
'; } else html += '
'; } } } } html += '
'; html += '
'; html += '
'; return html; } function renderAnnouncement(announcement) { const p_announcement_dismissed = getCookie('p_announcement_dismissed'); const u_announcement_dismissed = getCookie('u_announcement_dismissed'); if ((accountType === 'P' && (p_announcement_dismissed === "" || parseInt(p_announcement_dismissed) !== parseInt(announcement['record_id']))) || (accountType === 'U' && (u_announcement_dismissed === "" || parseInt(u_announcement_dismissed) !== parseInt(announcement['record_id'])))) { let html = ''; html += '
' + announcement['announcement_text']+ '
'; $('#announcement-container').empty().html(html); const announcementHeight = $('#announcement-container').height(); const mainNavBar = $('#main-navbar-nav'); const mainBody = $('#main'); const navBarHeight = mainNavBar.outerHeight(); const newBodyTopMargin = navBarHeight + announcementHeight + 10; mainNavBar.css('margin-top', announcementHeight); mainBody.css('margin-top', newBodyTopMargin); $('#close-announcement').on('click', function() { $('#announcement-container').remove(); mainNavBar.css('margin-top', 0); mainBody.css('margin-top', navBarHeight + 10); // set cookies to expire in one year if (accountType === 'P') { document.cookie = "p_announcement_dismissed=" + announcement['record_id'] + ";max-age=31536000"; } else if (accountType === 'U') { document.cookie = "u_announcement_dismissed=" + announcement['record_id'] + ";max-age=31536000"; } }); } } function generateLoginForm() { let html = ''; let e = getCookie('e'); html += '
'; html += '
'; html += '
'; // SUBDOMAIN LOGO html += '
'; if( subdomainLogoFile === '') { html += '

' + subdomainCompanyName + '

'; } else { html += ''; } html += '
'; // .login-form-logo-div // SUBDOMAIN TAGLINE if (subdomainCompanyTagLine !== '') { html += '
'; html += subdomainCompanyTagLine; html += '
'; // .login-form-tagline } // LOGIN FORM html += '
'; // EMAIL html += '
' if( e.length > 0 ) { html += ''; } else { html += ''; } html += ''; html += '
Please enter your email address
'; html += '
'; // form-floating // PASSWORD html += '
'; html += ' 0 ? 'autofocus' : '') + '>'; html += ''; html += '
Please enter your password
'; html += '
'; // mt-3 // REMEMBER ME html += '
'; html += ' 0 ? 'checked="checked"' : '') + '>'; html += ''; html += '
'; html += '
 
'; html += ''; html += 'I forgot my password'; html += '

or

'; html += ''; html += '

We\'ll email you a secure link for a one-time, password-free log in.

'; html += '
'; // #login-form-inputs // FOOTER html += ''; // #login-page-footer-info html += '
'; // col-4 html += '
'; html += '
'; html += '
'; // col-8 html += '
'; // row html += '
'; // container // return html; } function generateForgotPasswordForm() { let html = ''; return html; } function generateMagicLinkForm() { let html = ''; html += ''; // #login-magic-link-modal return html; } function loginForm() { var html = generateLoginForm(); html += generateForgotPasswordForm(); html += generateMagicLinkForm(); // $("#main").html(html); $('#main-page-bottom').hide(); initOutput(); $("#reset-password-link").on("click",function() { $("#btn-reset-password-submit").prop('disabled', false); $('#user_email_reset' ).val( $( '#user_email' ).val( ) ); }); $('#magic-link-btn').on('click', function() { $('#login-magic-link-email-input').val($('#user_email').val()); }); $("#btn-reset-password-submit").on("click",function() { passwordResetRequest(); }); $('#user_email_reset').on('keyup', function() { if ($(this).hasClass('is-invalid')) { $(this).removeClass('is-invalid'); } }); if( $("#btn-login-submit").length > 0 && $("#user_email").length > 0 && $("#user_password").length > 0 ) { $("#user_email, #user_password").on("keyup",function(e) { if ($(this).hasClass('is-invalid')) { $(this).removeClass('is-invalid'); } if( e.which === 13 ) /* 13 == enter key */ { loginAttempt(); } }); $("#btn-login-submit").on("click",function() { loginAttempt(); }); } $('#send-magic-link-btn').on('click', function() { let email = $("#login-magic-link-email-input").val(); if (email.length > 6) { let endpoint = '/generate_magic_link/'; let params = {}; params.user_email = email; let data = {}; data.params = params; postparams = encodeURIComponent(JSON.stringify(data)); ajaxCall(endpoint, params, function(json) { if (json.ErrorCode == 0) { $('#send-magic-link-msg').html('
Magic Link sent to ' + json.To + '!
'); } else { $('#send-magic-link-msg').html('
Oops! We couldn\'t send the Magic Link to this address.
'); } }); } else { $('#send-magic-link-msg').html('
Please enter a valid email address to send the Magic Link to.
'); } }); if (SERVER_NAME === 'www.mybodysite.com:88') { $('#watermark').html('QA'); } } function passwordResetRequest() { const emailInput = $("#user_email_reset"); const emailVal = emailInput.val(); if( emailVal.length > 0 ) { const submitBtn = $("#btn-reset-password-submit"); const endpoint = '/reset_password_request/' let reset_params = {} if( emailVal.length >= 6 ) { reset_params['params'] = {}; reset_params['params']['email'] = emailVal; const postparams = encodeURIComponent( JSON.stringify( reset_params ) ); $.ajax({ url:AJAXURI + endpoint, method:"POST", dataType:'JSON', data:{'data': postparams}, success:function(json) { if( json['status'] === 1 ) { $("#pw-message-reset").html('
' + nl2br( json['message'] ) + '
'); submitBtn.prop('disabled', true); } else if( json['status'] === 0) { $('#pw-message-reset').html('
'+nl2br(json['message'])+'
'); } } }); } else { emailInput.addClass('is-invalid'); } } else { emailInput.addClass('is-invalid'); } } function loginAttempt() { const emailInput = $("#user_email"); const passwordInput = $("#user_password"); const email = emailInput.val(); const pw = passwordInput.val(); const rem = $("#rem").prop("checked"); if( email.length > 6 && pw.length > 0 ) { $.ajax({ url: HTTP_PATH + '/login/', method:"POST", data: `grant_type=password&client_id=web_portal&username=${encodeURIComponent(email)}&password=${encodeURIComponent(pw)}`, success:function(json) { // go home $.ajax({ url: AJAXURI + '/home/', headers: { 'X-CSRF-Token': Math.random().toString(20).substr(2, 20) }, method:"POST", dataType:"JSON", success:function( json ) { $('#main').removeClass('login-form-main'); $('#main-page-bottom').show(); setDomainValues(json.domain_info) accountType = json.account_type; if (typeof(sessionMonitor) != 'undefined') { sessMon = sessionMonitor({ sessionLifetime: MAX_SESSION_LENGTH * 1000, timeBeforeWarning: TIMEOUT_WARNING_LENGTH * 1000 }); window.sessMon = sessMon; } if (rem) { document.cookie = "e=" + email; } else { deleteCookie('e'); } parseJSONresponse(json, 'body'); } }); }, error: function(xhr, status, errorThrown) { if (xhr.status === 401) { let response = xhr.responseJSON; if (response.hasOwnProperty('error') && response.hasOwnProperty('error_description') && response.error_description != '') { let errorMsg = response.error_description; $("#login-message").html('
' + nl2br( errorMsg ) + '
'); $("#user_email,#user_password").focus(function(){$("#login-message").html(' ');}); } } } }); } else { if( email.length < 6 ) { emailInput.addClass('is-invalid'); } if( pw.length < 1 ) { passwordInput.addClass('is-invalid'); } } } function resizeStuff() { if( $(window).width() < 992 ) { if( subdomainLogoFile !== '' && subdomainLogoFile != null) { $("#toggle_width").parent().hide(); if( $(window).width() < 768 ) $("#site_logo").attr("src",subdomainLogoFile); else $("#site_logo").attr("src",subdomainSplashFile); } else { $("#site_logo").parent().html(subdomainCompanyName); } } else { $("#toggle_width").parent().show(); if( subdomainLogoFile !== '' && subdomainLogoFile != null) { $("#site_logo").attr("src",subdomainLogoFile); } else { $("#site_logo").parent().html(subdomainCompanyName); } } if ($('nav#main-navbar-nav').length > 0) { const navBarHeight = $('nav#main-navbar-nav').outerHeight(); let mainBodyTopMargin = navBarHeight + 10; if ($('#announcement-container').length > 0) { const announcementHeight = $('#announcement-container').outerHeight(); mainBodyTopMargin = announcementHeight + navBarHeight + 10; } $('#main').css('margin-top', mainBodyTopMargin); } } function prepareJSONparams( object ) { return JSON.stringify(object).replace(/'/g,"'").replace(/"/g,"""); } function generateUUID() { var d = new Date().getTime(); var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = (d + Math.random()*16)%16 | 0; d = Math.floor(d/16); return (c=='x' ? r : (r&0x3|0x8)).toString(16); }); return uuid; } function nl2br( str ) { return (str != null) ? str.toString().replace(/\r\n/ig,"
").replace(/\n/ig,"
") : ''; } /* getTodayDateForDatePicker() usage: var sToday = getTodayDateForDatePicker(); returns "03/18/2016" */ function getTodayDateForDatePicker(options) { if (undefined !== options && options !== null) { return new Date().toLocaleDateString('en-US', options).replace(/\u200e/g, ''); } else { return new Date().toLocaleDateString().replace(/\u200e/g, ''); } } function getTodayDateForServer() { // the server expects the date in the US format, regardless of the user's actual locale let dateobj = new Date(); let month = (dateobj.getMonth() + 1); let date = dateobj.getDate(); let year = dateobj.getFullYear(); return month.toString() + '/' + date.toString() + '/' + year.toString(); } function formatLocalDate(datestr) { var d = datestr.replace(/\-/g,"/"); var date = new Date( d + " UTC" ); return date.toLocaleString(); } function formatLocalDateFromTimestamp(timestamp) { timestamp = parseInt(timestamp); const date = new Date(timestamp * 1000); return date.toLocaleString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric'}); } function formatLocalDateTime(timestamp) { let date = new Date(); if (undefined != timestamp && timestamp != null && timestamp > 0) { date = new Date(timestamp * 1000); } return date.toLocaleString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric'}); } function addModal( sModalID, sModalTitle, hModalBody, hModalFooter ) { var sNewModalBodyID = 'modal-body_'+sModalID; var modalhtml = ''; modalhtml += ''; // $("body").append( modalhtml ); const modal = new bootstrap.Modal('#' + sModalID); modal.show(); } function getCookie(cname) { var name = cname + "="; var ca = document.cookie.split(';'); for(var i=0; i .close').on('click', function() { let bannerID = $(this).attr('data-banner-id'); $('#' + bannerID).remove(); }); } } }); function renderBanner(packageID, companyName) { let html = ''; let bannerID = generateUUID() + '-app-banner'; html += '
'; html += ''; // .mobile banner html += '
'; html += '
'; return html; } $(document).ajaxComplete(function (evt, xhr, obj) { if (obj['dataType'] == 'script') { initOutput(); } else if (obj['dataType'] == 'JSON') { if (undefined !== window.sessMon) { if (xhr.getResponseHeader('X-Regenerate') && xhr.responseJSON.endpoint != window.sessMon.logoutUrl && xhr.responseJSON.endpoint != window.sessMon.pingUrl) { // because we've already "pinged" the server with the ajax call, we just need to extend the timers //window.sessMon.extendTimer(); } else if (xhr.responseJSON.endpoint == window.sessMon.logoutUrl) { window.sessMon.destroySess(); } } } }); $(window).on("resize",function() { resizeStuff(); }); resizeStuff(); function nowtimestamp() { return new Date().getTime(); } function timeAgo( datestr ) { if( datestr == '' ) { return "-"; } var periods = ["second", "minute", "hour", "day", "week", "month", "year", "decade"]; var lengths = ["60","60","24","7","4.35","12","10"]; var now = Math.round(new Date().getTime()/1000) + 10; var timestamp = datestr; // check validity of date if( timestamp == null ) { return "-"; } // is it future date or past date if(now > timestamp) { var difference = now - timestamp; var tense = "ago"; } else { var difference = timestamp - now; var tense = "from now"; } for(i=0;difference >= lengths[i] && i<(lengths.length-1);i++) { difference /= lengths[i]; } difference = Math.round(difference); if(difference != 1) { periods[i] += "s"; } return difference + ' ' + periods[i] + ' ' + tense; } function removeHash() { var scrollV, scrollH, loc = window.location; if ("pushState" in history) history.pushState("", document.title, loc.pathname + loc.search); else { // Prevent scrolling by storing the page's current scroll offset scrollV = document.body.scrollTop; scrollH = document.body.scrollLeft; loc.hash = ""; // Restore the scroll offset, should be flicker free document.body.scrollTop = scrollV; document.body.scrollLeft = scrollH; } } jQuery.fn.scrollTo = function(elem, padding ) { var offset = $(elem).offset().top - padding; $(this).animate({scrollTop:0}, 0).animate({ scrollTop: offset },0); return this; }; jQuery.fn.domsort = function() { var $list = $(this); $list.children().detach().sort(function(a, b) { return $(a).text().localeCompare($(b).text()); }).appendTo($list); }; // turn any textarea in to a tinyMCE editor jQuery.fn.tinymce = function(savebtn, contentLibraryUUID, codeEditor, toolbars) { savebtn = ( savebtn == true ) ? 'save' : null; let cancelBtn = this.hasAttr('data-cancel-btn') && this.attr('data-cancel-btn') == 'true'; let allowImages = this.hasAttr('data-allow-images') ? (this.attr('data-allow-images') == 'true') : true; let showCharacterCount = this.hasAttr('data-show-character-count') ? (this.attr('data-show-character-count') == 'true') : false; let characterLimit = this.hasAttr('data-character-limit') ? this.attr('data-character-limit') : null; let allowMedia = this.hasAttr('data-allow-media') ? (this.attr('data-allow-media') == 'true') : false; let showCode = (this.hasAttr('data-show-code') || codeEditor !== undefined) ? (this.attr('data-show-code') == 'true' || codeEditor === true) : false; let enableSaveBtn = (this.hasAttr('data-enable-save-btn') && this.attr('data-enable-save-btn') === 'true') ? false : true; let toolbar1 = "styleselect formatselect fontselect fontsizeselect " + (cancelBtn ? 'cancelbtn' : ''); let toolbar2 = "bold italic underline strikethrough hr | "; toolbar2 += "charmap | "; toolbar2 += "forecolor backcolor alignleft aligncenter alignright alignjustify | "; toolbar2 += "bullist numlist outdent indent blockquote | "; toolbar2 += "link unlink | "; var sInitPlugins = "autoresize, image, preview, textcolor, link, charmap, paste, save, lists, advlist, placeholder, hr"; if (allowImages) { toolbar2 += "image"; } if (allowMedia) { sInitPlugins += ", media"; toolbar2 += " media"; } if (showCode) { sInitPlugins += ", code"; toolbar2 += " code"; } toolbar2 += " | preview"; if (toolbars !== undefined && toolbars != null) { if (toolbars.hasOwnProperty('toolbar1') && toolbars.toolbar1 != null) { toolbar1 = toolbars.toolbar1; } if (toolbars.hasOwnProperty('toolbar2') && toolbars.toolbar2 != null) { toolbar2 = toolbars.toolbar2; } } var dom_id = this.attr("id"); if (showCharacterCount) { sInitPlugins += ", charactercount"; } let currentEditor = tinyMCE.get(dom_id); if (currentEditor != null && currentEditor.initialized == true) { currentEditor.remove(); } tinyMCE.init({ content_css: ["/css/bootstrap_cosmo.css", "/css/global.css?v=" + versionNum], selector:"#"+dom_id, entity_encoding:"named", theme:"modern", remove_trailing_brs: true, paste_as_text: true, menubar: false, statusbar: true, branding: false, autoresize_bottom_margin : 0, plugins:[ sInitPlugins ], toolbar1: toolbar1, toolbar2: toolbar2, toolbar3: savebtn, font_formats: 'Segoe UI="Segoe UI";Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats', image_advtab: false, image_description: false, image_class_list: [ { title: "Full Size", value: 'img-fluid' }, { title: "Fixed Size and Position", value:"rich-text-image" }, { title: "Centered", value: "center-image" }], image_prepend_url:HOME_URI, save_enablewhendirty: enableSaveBtn, save_onsavecallback:function() { let id = this.id; executeAjaxCall($('#'+id)); }, style_formats: [ { title: "Image Center", selector: 'img', classes: 'center-image' }, { title: "Full Width", selector: 'img', classes: 'w-100 h-auto m-0' }, { title: "Left with text", selector: 'img', classes: 'float-left mr-2' }, { title: "Right with text", selector: 'img', classes: 'float-right ml-2' } ], relative_urls : false, remove_script_host : false, convert_urls : true, forced_root_block : 'p', indent: false, media_alt_source: false, media_poster: false, keep_styles: false, extended_valid_elements: 'video[onclick|controlslist|controls]', video_template_callback: function(data) { let iframeSrc = data.source1; // There's a bug with the version of tinymce we're using that forces YouTube embeds to use a relative protocol. // For example the source will be set to "//www.youtube.com/embed/123456" instead of "https://www.youtube.com/embed/123456" // This causes no issues on the web as the browser automatically fetches the video via https, // but when embedding videos on the app, the missing protocol is causing the video to not be rendered. // In order to get around this until we update tinymce, I'm setting the URL for YouTube videos to one that // tinymce will not be able to automatically generate the embed code for so that it's forced to use this function to generate the embed code // and I can then create it manually and have it include the https. // https://github.com/tinymce/tinymce/issues/3889 const videoURL = new URL(iframeSrc); const host = videoURL.host; if (host === 'www.youtube.com') { const videoID = videoURL.pathname; iframeSrc = videoURL.protocol + '//' + videoURL.host + '/embed' + videoID + '?autoplay=0&rel=0&controls=1&allowsInlineMediaPlayback=1&playsinline=1&enablejsapi=1'; } let videoHtml = ''; videoHtml += '
`; videoHtml += '
'; return videoHtml; }, file_picker_callback: function(callback, value, meta/*field_name, url, type, win*/) { let type = meta.filetype; if (type === 'image') { tinymce.activeEditor.windowManager.open({ title: 'Select a photo...', file: imagebrowser, width: $("#mainbody").width() * 0.75, height: $(window).height() * 0.75, buttons: [{ classes:'btn btn-sm btn-success', text: 'Close', onclick: 'close' }], resizable : "yes", }, { setUrl: function(url) { callback(url, { height: 'auto', width: 'auto' }); } }); } else if (type === 'media') { tinymce.activeEditor.windowManager.open({ title: 'Select a video...', file: HTTP_PATH + '/video_browser/', width: $("#mainbody").width() * 0.75, height: $(window).height() * 0.75, buttons: [{ classes: 'btn btn-sm btn-success', text: 'Close', onclick: 'close' }], resizable: "yes", }, { setUrl: function (url) { callback(url); } }); } return false; }, setup:function(ed) { let editorID = $(ed).attr('id'); let editor = $('#' + editorID); ed.on('keyup change', function(e) { if (editor.hasAttr('data-save-button')) { let saveBtn = editor.attr('data-save-button'); $(saveBtn).prop('disabled', false).removeClass('btn-outline-secondary').removeClass('btn-secondary').addClass('btn-warning'); } if (editor.hasAttr('data-discard-changes-button')) { let discardBtn = editor.attr('data-discard-changes-button'); $(discardBtn).prop('disabled', false); } if (characterLimit != null) { let count = this.plugins["charactercount"].getCount(); if (count > characterLimit) { e.preventDefault(); e.stopPropagation(); return false; } } // editor on plan photos/notes/youtube/vimeo else if($("#"+dom_id).hasClass("content-object-data") && undefined != contentLibraryUUID) { toggleSaveChanges(true, contentLibraryUUID); } }); if (cancelBtn) { ed.addButton('cancelbtn', { text: 'Discard Changes', title: "Discard your changes and close the editor", onclick: function() { let editorID = $(ed).attr('id'); let showDiv = editor.attr('data-show-on-cancel'); $(showDiv).show(); let editToggle = $('*[data-toggle="edit_textarea"][data-target="' + showDiv + '"]'); if (editToggle.length > 0) { editToggle.prop('disabled', false).removeClass('disabled').show(); } tinyMCE.remove('#' + editorID); editor.remove(); } }); } }, init_instance_callback: function (editor) { $('.mce-tinymce').show('fast'); let editorDOM = $(editor.getContainer()); editorDOM.find(".mce-path").css("display", "none"); $('#' + dom_id + '_ifr').css('width', '99%'); let codeBtn = editorDOM.find('.mce-i-code').parent(); if (codeBtn.length > 0) { codeBtn.on('click', function (click_event) { //click_event.preventDefault(); click_event.stopPropagation(); let modalID = 'show-code-caution-modal'; let modalTitle = 'Be Careful!'; let modalText = 'Use the code editor at your own risk! While you can do some really cool stuff in here, make sure to check your work before saving your changes so we don\'t run into any trouble when we try to display your content.'; let modalFooter = ``; addModal(modalID, modalTitle, modalText, modalFooter); $('#' + modalID).on('hide.bs.modal', function() { codeBtn.trigger(click_event); }); }); } editor.on('NodeChange', function(e) { let changedElement = $(e.element); if (changedElement.is('img') && changedElement.attr('width') != 'auto' && changedElement.attr('height') != 'auto' && changedElement.hasClass('mt-2') === false) { changedElement.addClass('mt-2'); } }); } }); return $(this); }; function getSourceFromUrl(url) { let youtube_regex = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com(?:\/embed\/| \/v\/| \/watch\?v=))[\w-]{10,12}/; let vimeo_regex = /^(?:https?:\/\/)?(?:www\.)?(?:player.)?vimeo\.com\/(?:video\/)?[\d]+/; let wistia_regex = /https?:\/\/(?:.+)?(?:wistia\.com|wi\.st|wistia\.net)\/.*/; if (youtube_regex.test(url)) { return 'youtube'; } else if (vimeo_regex.test(url)) { return 'vimeo'; } else if (wistia_regex.test(url)) { return 'wistia'; } } /** * detect IE * returns version of IE or false, if browser is not Internet Explorer */ function isIE() { var ua = window.navigator.userAgent; var msie = ua.indexOf('MSIE '); if (msie > 0) { // IE 10 or older => return version number // return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); return true; } var trident = ua.indexOf('Trident/'); if (trident > 0) { // IE 11 => return version number var rv = ua.indexOf('rv:'); // return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); return true; } var edge = ua.indexOf('Edge/'); if (edge > 0) { // Edge (IE 12+) => return version number // return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); return true; } // other browser return false; } // Encode/decode htmlentities function htmlentitles_encode(str) { return $("
").text(str).html(); } function htmlentitles_decode(str) { return $("
").html(str).text(); } function embedVimeo( player_id, vimeoid ) { var embedhtml = '
'; embedhtml += '`; html += ''; html += '
'; // embed-responsive return html; } function embedVideo(video_source, player_id, video_source_ref_id) { let html = ''; switch (video_source.toUpperCase()) { case 'YOUTUBE': html += embedYouTube(player_id, video_source_ref_id); break; case 'VIMEO': html += embedVimeo(player_id, video_source_ref_id); break; case 'WISTIA': html += embedWistia(player_id, video_source_ref_id); break; } return html; } function escapeQuotes( str ) { return str.replace(/'/g,"'").replace(/"/g,"""); } function callYouTubePlayer(iframe, func, args) { if ( iframe.src.indexOf('youtube.com/embed') !== -1) { iframe.contentWindow.postMessage( JSON.stringify({ 'event': 'command', 'func': func, 'args': args || [] } ), '*'); } } jQuery.fn.visible = function() { $(this).css({"visibility":"visible"}); }; jQuery.fn.invisible = function() { $(this).css({"visibility":"hidden"}); }; function isNumberAlpha(field) { var re = /^[0-9- a-zA-Z]*$/; if (!re.test(field.value)) { field.value = field.value.replace(/[^0-9- a-zA-Z]/g,""); } } jQuery.fn.ForceNumericOnly = function() { return this.each(function() { $(this).keydown(function(e) { var key = e.charCode || e.keyCode || 0; // allow backspace, tab, delete, arrows, numbers and keypad numbers ONLY return ( key == 8 || key == 9 || key == 13 || key == 46 || (key >= 37 && key <= 40) || (key >= 48 && key <= 57) || (key >= 96 && key <= 105) || key == 110 || key == 190 ); }); }); }; jQuery.fn.ForceAlphaOnly = function() { return this.each(function() { $(this).keydown(function(e) { var key = e.charCode || e.keyCode || 0; // allow backspace, tab, delete, arrows, numbers and keypad numbers ONLY return ( key == 8 || key == 32 || key >= 65 && key <= 90 ); }); }); }; jQuery.fn.ForceTelephoneNumber = function() { return this.each(function() { $(this).keydown(function(e) { var key = e.charCode || e.keyCode || 0; // allow backspace, tab, delete, arrows, numbers and keypad numbers ONLY return ( key == 8 || key == 9 || key == 13 || key == 46 || (key >= 37 && key <= 40) || (key >= 48 && key <= 57) || (key >= 96 && key <= 105) || key == 109 || key == 110 || key == 189 || key == 190 ); }); }); }; // checks to see if an element has an attribute by attribute name jQuery.fn.hasAttr = function(attrName) { var attr = $(this).attr(attrName); return typeof attr != typeof undefined; }; function makeValidDOMID(str) { var validID = ''; validID = str.replace(/ ^[^a-z]+|[^\w:.-]+/gi, ""); return validID.toLowerCase(); } // returns a valid id from the chart name function makeChartNameValid(chart) { return makeValidDOMID(chart.toLowerCase().replace(/ |\/|\(|\)|\%/g, '_')); } function touchHandler(event) { var touch = event.changedTouches[0]; var simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent({ touchstart: "mousedown", touchmove: "mousemove", touchend: "mouseup" }[event.type], true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); touch.target.dispatchEvent(simulatedEvent); var $target = $(event.target); if( $target.hasClass('draggable') ) { // event.preventDefault(); } } function renderRecipeObject(oRecipeObject) { let html = ''; let iRecipeID = oRecipeObject['meal_id']; html += '
'; if( oRecipeObject.hasOwnProperty('meal_photo') && oRecipeObject['meal_photo'] != null ) { html += '
'; html += 'Recipe photo for ' + oRecipeObject.meal_display_name + ''; html += '
'; html += '
'; html += '
'; } else { html += '
'; } html += '

' + oRecipeObject['meal_display_name']; if (oRecipeObject.hasOwnProperty('replacement_meal') && oRecipeObject.replacement_meal === true) { html += ''; } html += '

'; html += renderRecipeFoodNutrition(iRecipeID, oRecipeObject); html += '
' + oRecipeObject['meal_description'] + '
'; html += '
'; html += '
'; if (oRecipeObject.hasOwnProperty('original_plan_day_meal') && oRecipeObject.original_plan_day_meal === true) { html += '
This is the recipe originally on your plan day.
'; } return html; } function renderRecipeFoodNutrition(iRecipeID, recipe) { var mealFoods = ''; let btnDisabled = (accountType !== 'U'? 'disabled' : ''); let hasAlternateMeals = ((recipe.hasOwnProperty('alternate_meals') && recipe.alternate_meals.length > 0) || (recipe.hasOwnProperty('has_alternate_recipes') && recipe.has_alternate_recipes === true)); if( recipe.meal_foods != null && recipe.meal_foods.length > 0) { var sFoods = ''; recipe.meal_foods.forEach((food) => { let servingLabel = makeFoodServingLabel(food['food_serving_name'], food['food_serving_count']); sFoods += '

' + food['food_name'] + '
' + servingLabel + '


' }); var mealfoodsmodal = 'meal_foods_modal_' + generateUUID(); var mealnutritionmodal = 'meal_nutrition_modal_' + generateUUID(); mealFoods += '
'; mealFoods += ''; mealFoods += ''; if (hasAlternateMeals) { mealFoods += ''; } if (recipe.hasOwnProperty('is_alternate_meal') && recipe.is_alternate_meal === true) { let jReplaceParams = [ { name: 'plan_day_object_id', value: recipe.plan_day_object_id }, { name: 'meal_id', value: recipe.meal_id } ]; mealFoods += ''; } else { mealFoods += ''; mealFoods += ''; } mealFoods += '
'; mealFoods += '';//.modal mealFoods += '';//.modal } else { if (recipe.hasOwnProperty('is_alternate_meal') && recipe.is_alternate_meal === true) { let jReplaceParams = [ { name: 'plan_day_object_id', value: recipe.plan_day_object_id }, { name: 'meal_id', value: recipe.meal_id } ]; mealFoods += ''; } else if (hasAlternateMeals) { mealFoods += ''; } } return mealFoods; } function renderPreviewRecipeNutrition(oRecipeFoods, numberOfServings) { var html = ''; var calories = 0; var fat = 0; var satfat = 0; var cholesterol = 0; var sodium = 0; var carb = 0; var fiber = 0; var sugar = 0; var protein = 0; var calcium = 0; for (let i in oRecipeFoods) { var food = oRecipeFoods[i]; calories += (food['food_serving_count'] * food['nutrition']['calories']) / numberOfServings; fat += (food['food_serving_count'] * food['nutrition']['fat']) / numberOfServings; satfat += (food['food_serving_count'] * food['nutrition']['satfat']) / numberOfServings; cholesterol += (food['food_serving_count'] * food['nutrition']['cholesterol']) / numberOfServings; sodium += (food['food_serving_count'] * food['nutrition']['sodium']) / numberOfServings; carb += (food['food_serving_count'] * food['nutrition']['carb']) / numberOfServings; fiber += (food['food_serving_count'] * food['nutrition']['fiber']) / numberOfServings; sugar += (food['food_serving_count'] * food['nutrition']['sugar']) / numberOfServings; protein += (food['food_serving_count'] * food['nutrition']['protein']) / numberOfServings; calcium += (food['food_serving_count'] * food['nutrition']['calcium']) / numberOfServings; } html += ''; return html; } function renderNutrionInfoTable(calories, fat, satfat, cholesterol, sodium, carb, fiber, sugar, protein, calcium) { var html = ''; html += ''; html += ''; html += ''; html += ''; html += ''; // cholesterol is always mg html += ''; // sodium is always mg html += ''; html += ''; html += ''; html += ''; html += ''; // calcium is always mg html += '
Calories:
' + Math.round(calories) + '
Fat:' + getNutrientDisplay(fat) + '
Sat fat:' + getNutrientDisplay(satfat) + '
Cholesterol:' + Math.round(cholesterol) + 'mg
Sodium:' + Math.round(sodium) + 'mg
Carbs:' + getNutrientDisplay(carb) + '
Fiber:' + getNutrientDisplay(fiber) + '
Sugar:' + getNutrientDisplay(sugar) + '
Protein:' + getNutrientDisplay(protein) + '
Calcium:' + Math.round(calcium) + 'mg
'; return html; } function getNutrientDisplay(grams) { var ret = ''; if (grams < 1 && grams != 0) { ret = Math.round(grams * 1000)+'mg'; } else { ret = Math.round(grams)+'g'; } return ret; } function renderExerciseObject( oExerciseData, replacedom, bEditing ) { bEditing = (undefined == bEditing) ? false : bEditing; var html = ''; var boxid = 'exercise-box-'+generateUUID(); if( oExerciseData.hasOwnProperty('exercise_title') && oExerciseData['exercise_title'] != null ) { if( replacedom !== 'previewmain' ) { html += '

' + oExerciseData['exercise_title'] + '

'; } else if( replacedom === 'plan-edit-day') { html += renderExerciseDescription( oExerciseData, replacedom ); } else { html += '

' + oExerciseData['exercise_title'] + '

'; } } if( replacedom !== 'previewmain' ) { html += renderExerciseDescription( oExerciseData, replacedom ); } if(bEditing == true) // exercise in plan day editor { html += '
'; html += '
'; html += '
'; var aMetrics = oExerciseData['exercise_metrics']; var sMetric0 = ''; var sMetric1 = ''; var sMetric2 = ''; var sMetric3 = ''; if (undefined != aMetrics && aMetrics.length > 0) { if (hasNum(aMetrics[0])) { sMetric0 = aMetrics[0]; } if (undefined != aMetrics[1] && !hasNum(aMetrics[1]) && exerciseMetric0Descriptors.indexOf(aMetrics[1]) >= 0) { sMetric1 = aMetrics[1]; } if (sMetric0 != '' && sMetric1 != '') { if (hasNum(aMetrics[2])) { sMetric2 = aMetrics[2]; } if (undefined != aMetrics[3] && !hasNum(aMetrics[3]) && exerciseMetric2Descriptors.indexOf(aMetrics[3]) >= 0) { sMetric3 = aMetrics[3]; } } } // amount of exercise html += ''; // amount type selector (reps, distance, time, etc) html += ''; // exercise load html += ''; // load type selector html += ''; html += '
'; html += '
'; html += '
'; // .row } else { if( oExerciseData.hasOwnProperty('exercise_metrics') && oExerciseData['exercise_metrics'] != null ) { html += '
'; html += ( undefined !== oExerciseData['exercise_metrics'][0] ) ? oExerciseData['exercise_metrics'][0] + ' ' : ''; html += ( undefined !== oExerciseData['exercise_metrics'][1] ) ? oExerciseData['exercise_metrics'][1] + ' ' : ''; html += ( undefined !== oExerciseData['exercise_metrics'][2] ) ? oExerciseData['exercise_metrics'][2] + ' ' : ''; html += ( undefined !== oExerciseData['exercise_metrics'][3] ) ? oExerciseData['exercise_metrics'][3] : ''; html += '
'; } } return html; } function renderExerciseDescription( oExerciseData, replacedom ) { var html = ''; if( undefined !== replacedom && oExerciseData.hasOwnProperty('exercise_description') && oExerciseData['exercise_description'] != null && replacedom !== 'program' && replacedom.indexOf("preview") == -1 ) { html += oExerciseData['exercise_description']; html += '
'; } // // check if this exercise is NOT being rendered on a Plan Preview if (undefined !== replacedom && replacedom !== 'program' && replacedom.indexOf("preview") == -1 ) { html += renderExerciseImagesVideo( oExerciseData ); } // return html; } function renderExerciseImagesVideo(oExerciseData) { var html = ''; // exercise images and video html += '
'; if (oExerciseData.hasOwnProperty('exercise_image_1') && oExerciseData.exercise_image_1 != MISSING_PHOTO) { html += '
'; html += ''; html += '
'; } if (oExerciseData.hasOwnProperty('exercise_video')) { html += '
'; // if flv/mp4 video if (oExerciseData['exercise_video']['type'] === 'mp4') { html += '
'; html += ''; html += '
'; // embed-responsive } else if (oExerciseData['exercise_video']['type'] === 'youtube' && oExerciseData.exercise_video.video_id != '') { var player_id = 'exercise_video' + generateUUID(); var youtubeid = oExerciseData['exercise_video']['video_id']; html += embedYouTube(player_id, youtubeid); } html += '
'; } if (oExerciseData.hasOwnProperty('exercise_image_2') && oExerciseData.exercise_image_2 != MISSING_PHOTO) { html += '
'; html += ''; html += '
'; } html += '
'; // return html; } function renderExercisePlanObject(oExerciseData, bEditMetrics) { let metrics = ''; let exerciseDescUUID = generateUUID(); let html = ''; bEditMetrics = (undefined !== bEditMetrics) ? bEditMetrics : false; if (!bEditMetrics && oExerciseData.hasOwnProperty('exercise_metrics') && oExerciseData['exercise_metrics'] != null && oExerciseData['exercise_metrics'].length > 0 && oExerciseData['exercise_metrics'][0] != '') { // if we have metrics AND they're not all blank for (k in oExerciseData['exercise_metrics']) { let thisMetric = oExerciseData['exercise_metrics'][k]; metrics += thisMetric+' '; } } //html += '
'; html += '
'; html += '
'; if (metrics != '') { html += '
'; html += '
'; html += ''+metrics+''; html += '
'; // col-md-12 html += '
'; // row } html += '
'; html += '
'; html += '

' + oExerciseData['exercise_title'] + '

'; html += '
'; // col-md-12 html += '
'; // row html += '
'; // card-header html += '
'; html += renderExerciseDescription(oExerciseData, 'exercise_details'); if (bEditMetrics) { html += '
'; html += '
'; html += '
'; var aMetrics = oExerciseData['exercise_metrics']; var sMetric0 = ''; var sMetric1 = ''; var sMetric2 = ''; var sMetric3 = ''; if (undefined != aMetrics && aMetrics.length > 0) { if (hasNum(aMetrics[0])) { sMetric0 = aMetrics[0]; } if (undefined != aMetrics[1] && !hasNum(aMetrics[1]) && exerciseMetric0Descriptors.indexOf(aMetrics[1]) >= 0) { sMetric1 = aMetrics[1]; } if (sMetric0 != '' && sMetric1 != '') { if (hasNum(aMetrics[2])) { sMetric2 = aMetrics[2]; } if (undefined != aMetrics[3] && !hasNum(aMetrics[3]) && exerciseMetric2Descriptors.indexOf(aMetrics[3]) >= 0) { sMetric3 = aMetrics[3]; } } } // amount of exercise html += ''; // amount type selector (reps, distance, time, etc) html += ''; // exercise load html += ''; // load type selector html += ''; html += '
'; html += '
'; html += '
'; // .row } html += '
'; // collapse html += '
'; // card //html += '
'; // col-md-12 return html; } function renderProtocolObject(obj, clinicDiscount) { let html = ''; let uuid = generateUUID(); clinicDiscount = (undefined !== clinicDiscount) ? clinicDiscount : 0; html += '
'; html += '
'; html += '

' + obj.name + '

'; html += '
'; // card-header html += '
'; if (obj.personal_message !== null && obj.personal_message !== '') { html += '
' + obj.personal_message + '
'; } if (obj.hasOwnProperty('recommendations') && obj.recommendations != null && obj.recommendations.length > 0) { obj.recommendations.forEach((recommended_product) => { html += renderRecommendationProduct(recommended_product, clinicDiscount); }); } html += '
'; // card-body html += '
'; // card return html; } function renderRecommendationProduct(recommended_product, discount) { let html = ''; html += '
  • '; html += '
    '; html += '
    '; html += `${recommended_product.product.name}`; html += '
    '; // col-3 html += '
    '; html += '

    ' + recommended_product.product.name + '

    '; html += '
    ' + recommended_product.product.brand.name + '
    '; if (discount !== null && discount > 0) { let patientPrice = (recommended_product.msrp * ((100 - discount) / 100)); html += '
    MSRP: $' + formatDecimal(recommended_product.msrp, 2) + ''; html += 'Patient Price: $' + formatDecimal(patientPrice, 2) + '
    '; } else { html += '
    MSRP: $' + formatDecimal(recommended_product.msrp, 2) + ''; } html += '
    '; // col-6 html += '
    '; if (recommended_product.hasOwnProperty('dosage') && recommended_product.dosage.amount != null && recommended_product.dosage.format != null && recommended_product.dosage.frequency != null) { html += '
    '; html += '

    Dosage Instructions:

    '; html += '
    ' + recommended_product.dosage.amount + ' ' + recommended_product.dosage.format + ' ' + recommended_product.dosage.frequency; if (recommended_product.dosage.additional_info !== '' && recommended_product.dosage.additional_info != null) { html += ' ' + recommended_product.dosage.additional_info; } html += '
    '; html += '
    '; } if (recommended_product.hasOwnProperty('units_to_purchase')) { html += '
    Quantity: ' + recommended_product.units_to_purchase + ' units
    '; } html += '
    '; // col-3 html += '
    '; // row html += '
  • '; // list-group-item return html; } function print_r(o) { return JSON.stringify(o,null,'\t').replace(/\n/g,'
    ').replace(/\t/g,'   '); } function iVeryTop(elems) { var maxIndex = 0; elems = (typeof(elems) !== 'undefined') ? elems : $("*"); $(elems).each(function() { maxIndex = (parseInt(maxIndex) < parseInt($(this).css('z-index'))) ? parseInt($(this).css('z-index')) : maxIndex; iTopZIndex = maxIndex + 1; }); return iTopZIndex; } jQuery.fn.center = function () { this.css("position","absolute"); this.css("top", "5px"); this.css("z-index", 5000); this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth()) / 2) + $(window).scrollLeft()) + "px"); return this; } function getUnits(system, metric) { var units = ''; switch (metric.toUpperCase()) { case 'WEIGHT': case 'FAT MASS': case 'MUSCLE MASS': units = (system == 'imperial') ? 'lbs' : 'kgs'; break; case 'HIPS': case 'WAIST': case 'CHEST': case 'ARMS': case 'THIGHS': case 'CALVES': units = (system == 'imperial') ? 'ins' : 'cm'; break; case 'BODY FAT %': units = '%'; break; case 'RESTING HEART RATE': units = 'BPM'; break; case 'BLOOD PRESSURE': units = 'S/D'; break; case 'BLOOD SUGAR (MG/DL)': units = 'mg/dL'; break; default: units = ''; } return units; } function debounce(func, wait, immediate) { var timeout; return function() { var context = this; args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; function renderNotificationTable(aNotificationSettings, iUserID) { var html = ''; var email = {name: 'method', value: 'email'}; var sms = {name: 'method', value: 'sms'}; var userID = {name: 'user_id', value: iUserID}; html += ''; // table headers html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; // table body html += ''; for (let i in aNotificationSettings) { let type = i; let settings = aNotificationSettings[type]; let emailCheckboxID = type+'-email-cb'; let emailChecked = (settings['email_status'] !== 'W') ? 'checked' : ''; let smsCheckboxID = type+'-sms-cb'; let smsChecked = (settings['sms_status']) ? 'checked' : ''; let pushCheckboxID = type+'-push-cb'; let pushChecked = (settings['push_status']) ? 'checked' : ''; html += ''; // LABEL html += ''; // EMAIL SETTINGS html += ''; // SMS SETTINGS html += ''; // PUSH NOTIFICATION SETTINGS html += ''; // text-center html += ''; } html += ''; html += '
    Notification TypeEmailSMSPush Notifications
    '+settings['label']+''; if (settings.allow_email) { const jEmailSettingParams = [ { name: 'notification_type', value: type }, { name: 'user_id', value: userID }, { name: 'checked', is_checked: emailCheckboxID }, { name: 'method', value: 'email' } ]; html += ''; } html += ''; if (settings.allow_sms) { const jSMSSettingParams = [ { name: 'notification_type', value: type }, { name: 'user_id', value: userID }, { name: 'checked', is_checked: smsCheckboxID }, { name: 'method', value: 'sms' } ]; html += ''; } html += ''; if (settings.allow_push) { const jPushSettingParams = [ { name: 'notification_type', value: type }, { name: 'user_id', value: userID }, { name: 'checked', is_checked: pushCheckboxID }, { name: 'method', value: 'push' } ]; html += ''; } html += '
    '; return html; } function drawBodyCompChart(aUserLogs, sUserDisplayUnits, sFromDate, sToDate, sChartContainerID) { // get logs var aWeightLogs = (aUserLogs.hasOwnProperty('weight') && aUserLogs['weight'].hasOwnProperty('logs')) ? aUserLogs['weight']['logs'] : null; var aMuscleMassLogs = (aUserLogs.hasOwnProperty('muscle mass') && aUserLogs['muscle mass'].hasOwnProperty('logs')) ? aUserLogs['muscle mass']['logs'] : null; var aFatMassLogs = (aUserLogs.hasOwnProperty('fat mass') && aUserLogs['fat mass'].hasOwnProperty('logs')) ? aUserLogs['fat mass']['logs'] : null; var aBodyFatPercLogs = (aUserLogs.hasOwnProperty('body fat %') && aUserLogs['body fat %'].hasOwnProperty('logs')) ? aUserLogs['body fat %']['logs'] : null; // are we calculating lean mass? var bCalculateLeanMass = (aWeightLogs && (aFatMassLogs || aBodyFatPercLogs)) ? true : false; var aChartDataArray = []; // data array for google chart var aHeader = []; // first item in data array, specifies what columns will be in the array // indexes of items in each row of the charts data array const iDateIndex = 0; var iWeightIndex = 0; var iMuscleMassIndex = 0; var iFatMassIndex = 0; var iLeanMassIndex = 0; var index = 0; // incremented, used to set other indexes // make the first (header) row of the data array aHeader[iDateIndex] = 'Date'; if (aWeightLogs) { index++; aHeader[index] = 'Weight'; iWeightIndex = index; } if (aMuscleMassLogs) { index++; aHeader[index] = 'Muscle Mass'; iMuscleMassIndex = index; } if (aFatMassLogs) { index++; aHeader[index] = 'Fat Mass'; iFatMassIndex = index; } if (bCalculateLeanMass) { if (aFatMassLogs == null) { index++; aHeader[index] = 'Fat Mass'; iFatMassIndex = index; } index++; aHeader[index] = 'Lean Mass'; iLeanMassIndex = index; } aChartDataArray.push(aHeader); var sThisDate = sFromDate; // sets the first date to start with // store the previous log values, to be used if there is no log for that metric for that date var fLastWeightVal = 0.00; var fLastMuscleMassVal = 0.00; var fLastFatMassVal = 0.00; var fLastBodyFatPercVal = 0.00; // incrementers for looping through the different sets of logs, we only advance through the logs if we have added a new value var w = 0; var x = 0; var y = 0; var z = 0; var nextWeightLogDate = (aWeightLogs != null) ? aWeightLogs[0]['date'] : null; var nextMuscleMassLogDate = (aMuscleMassLogs != null) ? aMuscleMassLogs[0]['date'] : null; var nextFatMassLogDate = (aFatMassLogs != null) ? aFatMassLogs[0]['date'] : null; var nextBodyFatPercLogDate = (aBodyFatPercLogs != null && aFatMassLogs == null) ? aBodyFatPercLogs[0]['date'] : null; // loop through each day starting with the earliest date we have logs for, ending with the last date we could possibly have logs for while (sThisDate != null) { var chartData = []; var bAdd = false; chartData[iDateIndex] = sThisDate; if (aWeightLogs && aWeightLogs[x] != undefined) { var fWeightVal = 0.00; if (Date.parse(aWeightLogs[x]['date']) == Date.parse(sThisDate)) { // add this value fWeightVal = formatDecimal(aWeightLogs[x]['value']); fLastWeightVal = fWeightVal; nextWeightLogDate = (aWeightLogs[x + 1] !== undefined) ? aWeightLogs[x + 1]['date'] : null; x++; bAdd = true; } else { fWeightVal = fLastWeightVal; } chartData[iWeightIndex] = parseFloat(fWeightVal); } else if (fLastWeightVal > 0) { chartData[iWeightIndex] = parseFloat(fLastWeightVal); } if (aMuscleMassLogs && aMuscleMassLogs[y] != undefined) { var fMuscleMassVal = 0.00; if (Date.parse(aMuscleMassLogs[y]['date']) == Date.parse(sThisDate)) { // add this value fMuscleMassVal = formatDecimal(aMuscleMassLogs[y]['value'], 2); fLastMuscleMassVal = fMuscleMassVal; nextMuscleMassLogDate = (aMuscleMassLogs[y + 1] !== undefined) ? aMuscleMassLogs[y + 1]['date'] : null; y++; bAdd = true; } else { fMuscleMassVal = fLastMuscleMassVal; } chartData[iMuscleMassIndex] = parseFloat(fMuscleMassVal); } else if (fLastMuscleMassVal > 0) { chartData[iMuscleMassIndex] = parseFloat(fLastMuscleMassVal); } if (aFatMassLogs && aFatMassLogs[z] != undefined) { var fFatMassVal = 0.00; if (Date.parse(aFatMassLogs[z]['date']) == Date.parse(sThisDate)) { // add this value fFatMassVal = formatDecimal(aFatMassLogs[z]['value'], 2); fLastFatMassVal = fFatMassVal; nextFatMassLogDate = (aFatMassLogs[z + 1] !== undefined) ? aFatMassLogs[z + 1]['date'] : null; z++; bAdd = true; } else { fFatMassVal = fLastFatMassVal; } chartData[iFatMassIndex] = parseFloat(fFatMassVal); chartData[iLeanMassIndex] = chartData[iWeightIndex] - fFatMassVal; } else if (fLastFatMassVal > 0) { chartData[iFatMassIndex] = parseFloat(fLastFatMassVal); chartData[iLeanMassIndex] = chartData[iWeightIndex] - fLastFatMassVal; } if (bCalculateLeanMass && aFatMassLogs == null) { if (aBodyFatPercLogs[w] != undefined) { // if we don't have fat mass logs to use, calculate the lean mass from the body fat % var fLeanMassVal = 0.00; var fFatMassVal = 0.00; if (Date.parse(aBodyFatPercLogs[w]['date']) == Date.parse(sThisDate)) { // add this value fFatMassVal = (aBodyFatPercLogs[w]['value'] * 0.01) * chartData[iWeightIndex]; fFatMassVal = formatDecimal(fFatMassVal, 2); fLeanMassVal = chartData[iWeightIndex] - fFatMassVal; fLeanMassVal = formatDecimal(fLeanMassVal, 2); fLastBodyFatPercVal = aBodyFatPercLogs[w]['value']; nextBodyFatPercLogDate = (aBodyFatPercLogs[w + 1] !== undefined) ? aBodyFatPercLogs[w + 1]['date'] : null; w++; bAdd = true; } else { if (fLastBodyFatPercVal > 0) { fFatMassVal = (fLastBodyFatPercVal * 0.01) * chartData[iWeightIndex]; fFatMassVal = formatDecimal(fFatMassVal, 2); fLeanMassVal = chartData[iWeightIndex] - fFatMassVal; fLeanMassVal = formatDecimal(fLeanMassVal, 2); } else { fFatMassVal = 0; fLeanMassVal = 0; } } chartData[iFatMassIndex] = parseFloat(fFatMassVal); chartData[iLeanMassIndex] = parseFloat(fLeanMassVal); } else if (fLastBodyFatPercVal > 0) { fFatMassVal = (fLastBodyFatPercVal * 0.01) * chartData[iWeightIndex]; fLeanMassVal = chartData[iWeightIndex] - fFatMassVal; fLeanMassVal = formatDecimal(fLeanMassVal, 2); fFatMassVal = formatDecimal(fFatMassVal, 2); chartData[iFatMassIndex] = parseFloat(fFatMassVal); chartData[iLeanMassIndex] = parseFloat(fLeanMassVal); } } var orderedNextDates = []; if (nextWeightLogDate) { orderedNextDates.push(nextWeightLogDate); } if (nextMuscleMassLogDate) { orderedNextDates.push(nextMuscleMassLogDate); } if (nextFatMassLogDate) { orderedNextDates.push(nextFatMassLogDate); } if (nextBodyFatPercLogDate) { orderedNextDates.push(nextBodyFatPercLogDate); } if (orderedNextDates.length > 0) { orderedNextDates.sort((a, b) => { let parsedA = Date.parse(a); let parsedB = Date.parse(b); if (parsedA > parsedB) { return 1; } else if (parsedA === parsedB) { return 0; } else { return -1; } }); sThisDate = orderedNextDates[0]; } else { sThisDate = null; } if (bAdd) { aChartDataArray.push(chartData); } } if (aChartDataArray.length > 1) { var chartData = google.visualization.arrayToDataTable(aChartDataArray); var seriesOptions = {}; if (iFatMassIndex > 0) { if (iMuscleMassIndex > 0) { var iMuscleSeries = parseInt(iMuscleMassIndex - 1); seriesOptions[iMuscleSeries] = {color: 'orange'}; } var iFatSeries = parseInt(iFatMassIndex - 1); seriesOptions[iFatSeries] = {color: 'red'}; } var options = { title: 'Body Composition', curveType: 'function', legend: {position: 'bottom'}, height: 500, vAxis: {minValue: 0}, chartArea: {width:'85%'}, series: seriesOptions }; var chart = new google.visualization.AreaChart(document.getElementById(sChartContainerID)); chart.draw(chartData, options); } } // checks to see if the given string contains a number // returns true if it does // returns false if not function hasNum(sIn) { if (undefined != sIn) { var type = typeof(sIn); if (type == 'string') { var match = sIn.match(/\d+/g); if (match != null) return true; else return false; } else if (type == 'number') { return true; } } else { return false; } } function userProfilePhotoExists(sPhotoURL) { if (sPhotoURL && sPhotoURL != NO_PHOTO) return true; else return false; } function nullToBlank(sIn) { if (sIn == null) return ''; else return sIn; } function getUserStatusString(iUserStatus) { var statusStr = ''; switch (iUserStatus) { case USER_STATUS_ACTIVATED: statusStr = 'Activated'; break; case USER_STATUS_UNACTIVATED: statusStr = 'Unactivated'; break; case USER_STATUS_DEACTIVATED: case USER_STATUS_PROVIDER_CREATED_DEACTIVATED: statusStr = 'Deactivated'; break; case USER_STATUS_ADMIN_CREATED_UNACTIVATED: statusStr = 'Unactivated (Admin Created)'; break; case USER_STATUS_PROVIDER_CREATED_UNACTIVATED: statusStr = 'Unactivated (Provider Created)'; break; case USER_STATUS_PROVIDER_CREATED_ACTIVATED: statusStr = 'Activated (Provider Created)'; break; case USER_SELF_ENROLLMENT: statusStr = 'Unactivated (Self Enrolled)'; break; case USER_STATUS_DISABLE_ACTIVATION_EMAILS: statusStr = 'Unactivated (Activation Emails Disabled)'; break; case USER_STATUS_NEEDS_EMAIL_VALIDATION: statusStr = 'Unactivated (Needs Email Validation)'; break; default: break; } return statusStr; } function renderClearFilterBtn(sTableID) { $("#"+sTableID+"_filter").find("input:first").wrap('
    '); $("#"+sTableID+"_filter").parent().addClass("col-xs-4"); $("#"+sTableID+"_filter").find("div.input-group:first").append(' '); $('#'+sTableID+'_filter-clear').off().on("click",function() { var oTable = $("#"+sTableID).DataTable(); oTable.search('').columns().search('').draw(); }); } function renderTodayIcon() { let today = new Date(); let html = ''+today.getDate()+''; return html; } function isSmallWindow() { if ($(window).width() < 768) { return true; } else { return false; } } function getAge(dateString) { var today = new Date(); var birthDate = new Date(dateString); var age = today.getFullYear() - birthDate.getFullYear(); var m = today.getMonth() - birthDate.getMonth(); if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } function updateCalorieData(date, eaten, burned, remaining) { $('.total_calories_consumed [data-date="+date+"]').text(Math.round(eaten)); $('.total_calories_burned [data-date="+date+"]').text(Math.round(burned)); $('.total_difference [data-date="+date+"]').text(Math.round(remaining)); } function getLogoPath(thirdPartyName) { let path = ''; switch (thirdPartyName.toLowerCase()) { case 'fitbit': path = fitbitLogo; break; case 'inbody': path = inbodyLogo; break; case 'withings': path = withingsLogo; break; case 'innotech': path = INNOTECH_LOGO; break; case 'apple health': path = APPLE_HEALTH_LOGO; break; case 'oura': path = OURA_LOGO; break; case 'iglucose': path = IGLUCOSE_LOGO; break default: break; } return path; } jQuery.fn.createDatePicker = function() { let options = { allowInput: true, dateFormat: 'm/d/Y' }; if (this.hasAttr('data-format')) { let formatParam = this.attr('data-format'); options.dateFormat = formatParam; } let dateVal = $(this).val(); options.defaultDate = new Date(dateVal); if (this.hasAttr('data-endpoint')) { let input = $(this); options.onChange = function() { executeAjaxCall(input); }; } if ($(this).hasAttr('data-time-picker') && $(this).attr('data-time-picker') === 'true') { $(this).css({ "width": "12em", "text-align": "center", "max-width": "12em" }); options.enableTime = true; options.dateFormat = 'm/d/Y h:i K'; } else { $(this).css({ "width": "10em", "text-align": "center", "max-width": "10em" }); } $(this).flatpickr(options); this.addClass('datepicker-initialized'); return this; }; function makeFoodServingLabel(servingName, numServings) { // look for any number of digits, zero or one decimal, followed by any number of digits // ex. 6 medium or 0.25 cup // in order to get the number of items in the current serving servingName = servingName.toString(); let regExp = /^\d*\.?\d*/; let match = regExp.exec(servingName); if (match != null && match != '') { let servingNameNumServings = match * numServings; servingName = servingName.replace(regExp, servingNameNumServings); } else { servingName = numServings + ' ' + servingName; } return servingName; } function renderFoodPhoto(food) { let html = ''; let hasPhoto = (food.hasOwnProperty('food_photo') && food['food_photo'] != null && food['food_photo'].search('nix-apple-grey.png') == -1); if (hasPhoto) { html += '' + food['food_name'] + ''; } else { html += '
    '; } return html; } function reSortDataTable(sTableID) { // get the current filter var sFilter = $("#" + sTableID + "_filter").find("input:first").val(); // get the table object and it's settings var oTable = $("#" + sTableID).DataTable(); var initSettings = oTable.init(); // destroy the current table oTable.destroy(); // init new table $("#" + sTableID).DataTable(initSettings); renderClearFilterBtn(sTableID); // put the filter back in the search box $("#" + sTableID + "_filter").find("input:first").val(sFilter); // search with the filter var oTable = $("#" + sTableID).DataTable(); oTable.search(sFilter).draw(); // 'hack' for when there's no rows left after the filter is applied if ($("#" + sTableID + " tbody").find("td:first").hasClass("dataTables_empty")) { $("#" + sTableID + " tbody").find("td:first").attr("colspan", 2); } } function makePageHeader(sPageTitle, sEndpoint, sReplaceDOM, aParams, bShowWaiter) { let html = ''; bShowWaiter = (undefined === bShowWaiter) ? false : bShowWaiter; html += '

    '; html += sPageTitle; if (undefined !== sEndpoint) { html += ']*>/gi; let output = input.replace(regex, "\n"); return output; } function activateTab(tab) { const bsTab = new bootstrap.Tab(tab); bsTab.show(); } function goToNavItem(endpoint) { const navItem = $("#mainnavul a[data-endpoint='/" + endpoint + "/']"); const bsNavItem = new bootstrap.Tab(navItem); bsNavItem.show(); objectClick(navItem); } function closeModal() { return ''; } function formatPhoneNumber(phoneNumberString) { let cleaned = ('' + phoneNumberString).replace(/\D/g, ''); let match = cleaned.match(/^(1|)?(\d{3})(\d{3})(\d{4})$/); if (match) { let intlCode = (match[1] ? '+1 ' : ''); return [intlCode, '(', match[2], ') ', match[3], '-', match[4]].join(''); } return ''; } function strCompare(strA, strB) { // do both strings begin with numbers let numPatt = /^\d+/; if (numPatt.test(strA) && numPatt.test(strB)) { // compare the numbers let numA = numPatt.exec(strA); numA = parseInt(numA[0]); let numB = numPatt.exec(strB); numB = parseInt(numB[0]); if (numA < numB) { return -1; } else if (numA > numB) { return 1; } else { return 0; } } else { // just compare the strings if (strA.toUpperCase() < strB.toUpperCase()) { return -1; } else if (strA.toUpperCase() > strB.toUpperCase()) { return 1; } else { return 0; } } } jQuery.fn.initWistiaUploader = function() { let uploader_id = $(this).attr('id'); window._wapiq = window._wapiq || []; _wapiq.push(function (W) { window.wistiaUploader = new W.Uploader({ accessToken: WISTIA_ACCESS_TOKEN, dropIn: uploader_id, beforeUpload: function() { return { then: function(resolve, reject) { setTimeout(function() { // create a project to upload to $.ajax({ url: AJAXURI + '/get_wistia_project_id/', method: 'POST', dataType: 'JSON', headers: { 'X-CSRF-Token': Math.random().toString(20).substr(2, 20) }, success: function(json) { if (json.status == 1) { wistiaUploader.setProjectId(json.data.wistia_project_id); resolve(); } else { console.log(json.message); reject(); } }, error: function(xhr) { console.log(xhr); reject(); } }) }, 1000); } } } }); wistiaUploader.bind('uploadstart', function(file) { let html = ''; html += '
    Your video is uploading! Don\'t navigate away from this page until it finishes.
    '; $(html).insertAfter('#' + uploader_id); }); wistiaUploader.bind('uploadsuccess', function(file, media) { // add the video to the user's library via ajax let params = {}; params['params'] = {}; params['params']['video_source_ref_id'] = media.id; params['params']['video_thumbnail_href'] = media.thumbnail.url; params['params']['video_description'] = media.name; ajaxCall('/add_uploaded_video_to_library/', params, function(json) { let html = ''; if (json.status == 1) { $('#add-video-modal').find('button.close').addClass('abtn').attr('data-endpoint', '/video_library/').attr('data-replace-dom', 'videos'); let jChangeNameParams = []; jChangeNameParams.push({ name: 'video_name', value_of: 'change-uploaded-video-name' }); jChangeNameParams.push({ name: 'video_ref_id', value: media.id }); html += '
    '; html += 'Your video has been successfully uploaded and added to your library!

    '; html += ''; html += '
    '; html += ``; html += ``; html += '
    '; // input-group html += '
    '; // alert } else { html += '
    '; html += 'Oops! There was a problem adding this video to your library'; html += '
    '; // alert } $('#' + uploader_id + '_message').html(html); }); }); }); }; function parseDate(str) { var mdy = str.split('/'); return new Date(mdy[2], mdy[0]-1, mdy[1]); } function datediff(first, second) { // Take the difference between the dates and divide by milliseconds per day. // Round to nearest whole number to deal with DST. return Math.round((parseDate(second)-parseDate(first))/(1000*60*60*24)); } function getSelectedRadioVal(btnObjects) { let ret = ''; btnObjects.each(function() { let btn = $(this); if (btn.prop('checked') === true) { ret = btn.val(); } }); return ret; } function handleTableSearch(table_id) { let oTable = $("#" + table_id).DataTable(); let timerName = generateUUID() + '_timer'; window[timerName] = null; $('#' + table_id + '_filter input').off().on('keyup', function() { if (window[timerName] != null) { clearTimeout(window[timerName]); } let searchVal = $(this).val(); // we don't want to hit the database with the user's answer every single time they press a key // so wait 1 second and then trigger event that will save the answer window[timerName] = setTimeout(function() { oTable.search(searchVal).draw(); }, 750); }); } function makeTaskNameStr(task, viewing) { let name = ''; viewing = (undefined !== viewing) ? viewing : false; if (task.action != undefined) { switch (task.action) { case "/save_new_body_log/": if (task.hasOwnProperty('action_params') && task.action_params.hasOwnProperty('metric_name')) { name = 'Track ' + task.action_params.metric_name.toLowerCase(); } else { name = 'Track a body metric'; console.log('Task ' + task.task_id + ' missing metric name'); } break; case "/save_body_goal/": if (task.hasOwnProperty('action_params') && task.action_params.hasOwnProperty('metric_name')) { name = 'Set a ' + task.action_params.metric_name.toLowerCase() + ' goal'; } else { name = 'Set a body metric goal'; console.log('Task ' + task.task_id + ' missing metric name'); } break; case "/save_activity/": case "/track_custom_activity/": if (task.hasOwnProperty('action_params') && task.action_params.hasOwnProperty('activity_title')) { name = 'Track ' + task.action_params.activity_title.toLowerCase(); } else { name = 'Track an activity'; console.log('Task ' + task.task_id + ' missing activity title'); } break; case "custom": if (task.hasOwnProperty('action_params') && task.action_params.hasOwnProperty('prompt')) { name = task.action_params.prompt; if (!viewing) { if (task.action_params.completion === 'checkbox') { name += ''; } else if (task.action_params.completion === 'feedback') { name += ''; } } } else { name = 'Custom Task'; console.log('Task ' + task.task_id + ' missing prompt'); } break; case "/track_sleep/": name = 'Track sleep'; break; case "/track_steps/": name = 'Track steps'; break; case "/track_water/": name = 'Track water intake'; break; default: let selAction = ACTION_CHOICES.filter(function (choice) { return choice.endpoint === task.action; }); if (selAction.length === 1) { name = selAction[0].action; } break; } } else { switch (task.plan_object_type) { case 'NOTE': name = 'Read program content'; break; case 'EXERCISE': name = 'Did an exercise'; break; case 'YOUTUBE': case 'VIMEO': case 'WISTIA': name = 'Watched a video'; break; default: break; } } return name; } function toBool(str) { return str.toLowerCase() === 'true'; } function loadScript(sFileName, fnCallback) { if (undefined === fnCallback) { fnCallback = function() { void(0); }; } if (!window.scripts_loaded.includes(sFileName)) { $.ajax({ url: scriptbase + sFileName, dataType: 'script', success: fnCallback, async: true, complete: function (xhr, status) { window.scripts_loaded.push(sFileName); }, error: function(xhr, status, error) { console.log(error); } }); } else { fnCallback.call(null); } initOutput(); } function makePOSTParams(params) { return encodeURIComponent(JSON.stringify(params)); } function formatMacroTotal(val) { return (val < 1 && val > 0) ? '< 1' : Math.round(val); } function renderBAAForSignature(json) { let html = ''; $.getScript('https://cdncf.esignatures.io/assets/iframeResizer.4.2.10.min.js'); html += ''; // modal $('body').append(html); $('#sign-baa-modal').modal({ backdrop: 'static', keyboard: false, }).modal('show'); let modalBodyElement = document.querySelector('#sign-baa-modal .modal-body'); modalBodyElement.onscroll = function(event) { if ((modalBodyElement.scrollTop) === (modalBodyElement.scrollHeight - modalBodyElement.offsetHeight)) { // we're at the bottom, enable the button $('#done-signing-baa-button').prop('disabled', false).removeClass('disabled'); } }; } function checkContractSignedCallback(json, replacedom) { if (json.status === 1) { $('#' + replacedom).modal('hide').removeModal(true); if (json.data.contract_status === 'WITHDRAWN') { let html = ''; html += ''; // modal $('body').append(html); $('#user-withdrawn-opt-out').modal({ backdrop: 'static', keyboard: false }).modal('show'); } } } function renderBBABlockerModalForNonDomainAdmin(json) { let html = ''; let domainAdminUser = json.data.domain_admin_info; html += ''; // modal $('body').append(html); $('#needs-baa-signed-modal').modal({ backdrop: 'static', keyboard: false, }).modal('show'); } function optOutOfBAACallback(json) { if (json.status === 1) { $('#sign-baa-modal').modal('hide').removeModal(true); } } function timePassed(timestamp, start) { start = (undefined !== start) ? start : Math.round(new Date().getTime()/1000); let difference = start - timestamp; let seconds = difference; let minutes = Math.floor(difference / 60); seconds = (seconds - (minutes * 60)); let hours = Math.floor(minutes / 60); minutes = (minutes - (hours * 60)); if (seconds < 10) { seconds = '0' + seconds; } if (minutes < 10) { minutes = '0' + minutes; } if (hours < 10) { hours = '0' + hours; } return hours + ':' + minutes + ':' + seconds; } function renderStaffPermissionsOptions(userID, currentPermissions, parentDiv, domainMessagingEnabled) { let tmpHtml = ''; tmpHtml += '
    '; // PATIENT MANAGEMENT tmpHtml += '
    '; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += '
    '; // form-group tmpHtml += '
    '; if (domainMessagingEnabled) { // MESSAGING tmpHtml += '
    '; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += '
    '; // form-group tmpHtml += '
    '; } // PATIENT ENROLLMENT tmpHtml += '
    '; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += '
    '; // form-group tmpHtml += '
    '; // CONTENT MANAGEMENT tmpHtml += '
    '; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += '
    '; // form-group tmpHtml += '
    '; // FULL ADMIN tmpHtml += '
    '; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += ''; tmpHtml += '
    '; tmpHtml += '
    '; // form-group tmpHtml += '
    '; tmpHtml += '
    '; // row $('#' + parentDiv).html(tmpHtml); $('.ui.checkbox').checkbox(); $('.team-member-permissions-checkbox').on('change', function() { const userID = $(this).attr('data-team-member-user-id'); let selectedPermissions = []; const checkedPermissionsBoxes = $('.team-member-permissions-checkbox[data-team-member-user-id="' + userID + '"]:checked'); if (checkedPermissionsBoxes.length > 0) { checkedPermissionsBoxes.each(function () { selectedPermissions.push($(this).attr('data-permission')); }); } else { selectedPermissions.push('NONE'); } let params = {}; let endpoint = '/provider_update_staff_permissions/'; params.endpoint = endpoint; params.params = {}; params.params.team_member_user_id = userID; params.params.permissions = selectedPermissions; ajaxCall(endpoint, params); }); } function officeDiscussionTimeAgo(utc_timestamp) { const nowTimestamp = (new Date().getTime()) / 1000; const diff = nowTimestamp - utc_timestamp; if (diff >= 86400 /* # of seconds in a day */) { const timestampDate = new Date(utc_timestamp * 1000); return timestampDate.toLocaleString('en-US', {month: '2-digit', day: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric'}); } else { return timeAgo(utc_timestamp); } }