/* ---------- Other Stuff ---------- */ isMobile = ('ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)); if (typeof webkitSpeechRecognition != 'undefined' || typeof SpeechRecognition != 'undefined') { var speechRecognitionApi = webkitSpeechRecognition || SpeechRecognition window.recognition = new webkitSpeechRecognition(); } // Time in ms that distinguishes between a click and a hold var holdMinTime = 500; // List of all the months in name form and number form const months = { January: '01', February: '02', March: '03', April: '04', May: '05', June: '06', July: '07', August: '08', September: '09', October: '10', November: '11', December: '12', } // old script for voice recognition $(document).on('click', '.recordVoice', function() { var recordButton = $(this); var input = $(recordButton.data('input')); if (!input) { input = $(this).closest('.input-group').find('input:not([type="submit"]), textarea'); } var recognition = new webkitSpeechRecognition(); recognition.lang = "en-US"; $('#stopVoiceRecording').click(function() { recognition.stop(); }); recognition.onresult = function(event) { var transcript = event.results[0][0].transcript; if (input.val() == '' && recordButton.data('date') != 'True'){ var value = transcript.charAt(0).toUpperCase() + transcript.slice(1); } else { if (recordButton.data('part-number') == 'True'){ value = input.val() + ' ' + transcript.toUpperCase().replace(/ /g, ''); } else if (recordButton.data('date') == 'True'){ var monthAndDay = transcript.split(', ')[0] var year = transcript.split(', ')[1].slice(0, -1) var month = monthAndDay.split(' ')[0] var day = monthAndDay.split(' ')[1].replace(/\D/g, ""); if (day.length == 1){ day = '0' + day } var monthNum = months[month] var formattedDateStr = year + '-' + monthNum + '-' + day value = formattedDateStr; } else if (input.val()[input.val().length -1] == '.'){ value = input.val() + ' ' + transcript.charAt(0).toUpperCase() + transcript.slice(1); } else { value = input.val() + ' ' + transcript; } } input.val(value); } recognition.onerror = function(error){ recognition.stop(); console.log(error) flash_error('There was an error with the voice recognition api.'); $('#micModal').modal('hide'); }; recognition.onend = function(){ recognition.stop(); console.log('modal'); $('#micModal').modal('hide'); }; recognition.start(); $('#micModal').modal('show'); }); // script for voice recognition $(document).on('mousedown', '.holdVoiceRec', function(event) { if (!window.recognition) return flash("Look like your browser doesn't support voice recognition.", "danger") var voiceInput = $($(this).data('input')) var that = event.currentTarget; $(that).addClass('recording') window.holdVTTBtn = false window.holdVTTBtnTimeout = window.setTimeout(function (){ window.holdVTTBtn = true $(that).popover('hide') }, holdMinTime); // handle voice recognition window.recognition.interimResults = true; window.recognition.continuous = true; window.recognition.lang = "en-US"; window.recognition.start(); var beginningText = voiceInput.val(); window.recognition.onresult = function (e) { const text = Array.from(e.results) .map((result) => result[0]) .map((result) => result.transcript) .join(" "); console.log(text) console.log(e.results) var fullText = `${beginningText} ${text}` if (text.includes("Cleartext.") || text.includes("Clear text.")) { return voiceInput.val("") } // If part number input then every letter is uppercase and there are no spaces and periods if ($('.holdVoiceRec').data('part-number') == "True") { fullText = fullText.toUpperCase().replace(/ /g, '').replace(/\./g, ''); } voiceInput.val(fullText)[0].scrollLeft = voiceInput[0].scrollWidth }; // handle css styling $(that).addClass('recording') }).on('click', '.holdVoiceRec', function(event) { if (!window.recognition) return ; window.recognition.stop(); // check to see if user held the vtt btn or just pressed it var that = event.currentTarget; window.clearTimeout(window.holdVTTBtnTimeout) if (!window.holdVTTBtn) { event.stopPropagation(); $(that).popover('show') } // handle css styling $(that).removeClass('recording') }); $('.holdVoiceRec').popover({ html: true, content: $('#vtt-popover').html(), trigger: 'manual', placement: 'top' }); /* ---------- Keyboard Shortcuts ---------- */ $(document).on('keyup', function(event) { if (!$(event.target).is(':not(input, textarea)')) return; if (event.key == "[") return $('.side-menu').trigger('toggle'); if (event.key == "]") return $('#show-notification-center').click(); if (event.key == "ArrowLeft") return changeTab('prev'); if (event.key == "ArrowRight") return changeTab('next'); }) function changeTab(direction) { var activeTabGroup = ($('.nav-tabs.active').length != 0) ? $('.nav-tabs.active') : $('.nav-tabs:first'); var currentOpenTab = activeTabGroup.find('.nav-item.hms-nav-item a.active').parent() if (currentOpenTab.length == 0) return; var newTab = currentOpenTab[direction]('.nav-item.hms-nav-item:visible') if (newTab.length == 0) return; // $('.tab-pane.active.show').each(function(){ // if ($(this) != newTab) return $(this).removeClass('active show') // }) newTab.find('a').click() } /* ---------- Toggle Side Menu ---------- */ $('.side-menu').on('toggle', function(){ $(this).toggleClass("hidden") $.post("/AJAX/ajax_set_user_preferences", {"side_menu_view": ($(this).hasClass('hidden')) ? 'hidden' : ''}); }) $(document).click("*:not(.popover) *", function(event){ var popoverChild = $(event.target).closest('.popover').length != 0 if (popoverChild) return; $('.popover').popover('hide') }) $('*').on('highlight', function(event){ event.stopPropagation() $(this).addClass("highlight") var that = this return setTimeout(function(){ $(that).removeClass('highlight') }, 2000) }) $(document).on("keydown", function (e) { if (e.originalEvent.code != "ShiftLeft") return; $('.show-shift-left').removeClass('d-none'); }); $(document).on("keyup", function (e) { if (e.originalEvent.code != "ShiftLeft") return; $('.show-shift-left').addClass('d-none'); }); $('input[type="range"]').on('input', function (){ $(this).closest('.input-group').find('.range-data').text($(this).val()); }); $(function() { // Open the tab with the id of g.active_tab or urlParams.get('activeTab') var queryString = window.location.search; var urlParams = new URLSearchParams(queryString); var activeTab = urlParams.get('activeTab') if (activeTab) { activateTab(activeTab); } // Show hidden tabs var showHiddenTabs = urlParams.get('showHiddenTabs') if (showHiddenTabs) { $(`#${showHiddenTabs} .toggleTabs`).trigger('click') } // Start page tour var tourNum = window.localStorage.getItem('tourNum') if (tourNum) { window.localStorage.removeItem('tourNum') startTour(tourNum) } // Set field values from g.field_vals $('textarea').each(function() { if ($(this).attr("value")) { $(this).text($(this).attr("value")); } }); var thisUrl = new URL(window.location) if (thisUrl.searchParams.get('iframe_title') && thisUrl.searchParams.get('iframe_url')) { // If there are perams in the url for an iframe link, then open it here var iframe_url = new URL(thisUrl.searchParams.get('iframe_url')) if (thisUrl.origin != iframe_url.origin) { var iframe_url = new URL('https://myhmshome.com/') } setIframeUrl( thisUrl.searchParams.get('iframe_title'), iframe_url.href ) } /* Scroll into view */ if ($(".scrollIntoView").length > 0) { $('html, body').animate({ scrollTop: $(".scrollIntoView").offset().top - 200 }, 300, 'easeInOutQuad'); } }); function activateTab(tab){ $(`.nav-tabs a[href="#${tab}"] + span`).trigger('click'); }; if ( window.location !== window.parent.location ) { var removeClassesForIframe = document.querySelectorAll(".remove-classes-for-iframe"); for (var i=0; i -1); }); }); $('.show-password').click(function(){ var $input = $($(this).data('input')); $(this).toggleClass('fa-eye'); $(this).toggleClass('fa-eye-slash'); if ($input.attr('type') == 'text'){ $input.attr('type', 'password'); } else { $input.attr('type', 'text'); } }); var hideAll = function() { $('div[class^=option]').hide(); } $('#select').change(function() { hideAll(); $('.' + $(this).val()).show(); }); $('[data-spy="scroll"]').each(function() { var $spy = $(this).scrollspy('refresh') }); $(function() { $('[data-toggle="popover"]').popover() }); $('.clear-ls').click(function(event) { window.localStorage.clear(); $('#unsaved-visit-toast').toast('hide'); }); $(function() { $('[data-toggle="tooltip"]').tooltip() }); function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); } $(".remedial-table-search").on('keydown', function() { var value = $(this).val().toLowerCase(); $(this).closest("tbody").children('tr:not(.search)').each(function() { $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1); }); }); $(document).on('click', '.show-wifi-pass', function(event) { $(this).closest('.input-group').find('input').attr('type', 'text'); $(this).removeClass('fa-eye'); $(this).addClass('fa-eye-slash'); $(this).addClass('hide-wifi-pass'); $(this).removeClass('show-wifi-pass'); }); $(document).on('click', '.hide-wifi-pass', function(event) { $(this).closest('.input-group').find('input').attr('type', 'password'); $(this).addClass('fa-eye'); $(this).removeClass('fa-eye-slash'); $(this).addClass('show-wifi-pass'); $(this).removeClass('hide-wifi-pass'); }); $(function(){ $('.map-iframe').html(function(){ var iframe = ``; return iframe; }); $('.google-maps-link').each(function() { address = $(this).data('address'); link = `https://www.google.com/maps/place/${encodeURIComponent( address )}`; $(this).attr('href', link); }); $('.duck-duck-go-maps-link').each(function() { address = $(this).data('address'); link = `https://duckduckgo.com/?q=${encodeURIComponent( address )}&atb=v257-1&ia=maps&iaxm=maps`; $(this).attr('href', link); }); // $('.calendar-date').attr("href", function(){ // $(this).attr('target', "_blank"); // var year = $('this').data('year'); // var month = $('this').data('month'); // var day = $('this').data('day'); // var link= `https://calendar.google.com/calendar/r/day/${year}/${month}/${day}`; // return link; // }); var thList = document.getElementsByClassName("sort-first-last"); for (var indexFirstLast=0; indexFirstLast 1){ e.preventDefault(); } }) // Edit Image Name on double click $(document).on('dblclick', '.image-name', function() { // Get the imageId and run editImage var imageId = $(this).closest('.image-row').data('image-id') editImage(imageId) }) function saveImage(imageId) { var $imageRow = $(`#image_${imageId}`) var imageFilename = $imageRow.find('textarea').val() jsonAjax({ "url": "/AJAX/rename_image", "json": { "image_id": imageId, "new_image_name": imageFilename }, catch_error: true, default_error: 'There was an error updating that image' }).done(function(data){ $imageRow.find('.image-name, .image-edit-name').toggleClass('d-none') $imageRow.find('.update-btns button').toggleClass('d-none') $imageRow.find('.image-name').text(imageFilename) flash('Image Saved') }) } $(document).on('click', '.save-image', function() { var imageId = $(this).closest('.image-row').data('image-id') saveImage(imageId) }) $(document).on('keydown', '.image-row textarea', function(event) { if (event.key != 'Enter') return; var imageId = $(this).closest('.image-row').data('image-id') saveImage(imageId) return false }) $('#sendFeedback').on('show.bs.modal', function(event) { $(this).find('textarea').val(dataRelatedTarget(event, 'feedback')); }); function flash(message, color='success', seconds=4) { // Make all error messages last at least 15 seconds if (color == 'danger' && seconds < 15) seconds = 15; // The default color passed by flask is "message" // Here I change the default to success if (color == 'message') color = 'success'; var $flashContainer = $('.flash-container'); // Render the message Dom element var flashMessage = $(` `) // #content-wrapper padding // Animate the element through jQuery flashMessage.animate({right: "7.5rem", opacity: "0.8"}, 400); flashMessage.animate({right: "7rem", opacity: "1"}, 100, function(){ setTimeout(function(){ var checkHover = setInterval(function(){ if (flashMessage.is(":hover")) return; flashMessage.animate({right: String(flashMessage.width() * -1) + "px"}, 350, function(){ clearInterval(checkHover) }); flashMessage.slideToggle(350, function(){ flashMessage.remove() }); }, 200) }, seconds * 1000) }); // Append the Dom element to the flash message container $flashContainer.append(flashMessage) } function flash_error(message, reported_message=message) { html_message = `${message} If this error persists, please report it ` console.error(message) return flash(html_message, "danger", 10) } function decodeSignedJson(key) { var encodedDict = key.split('.')[0] decodedDict = atob(encodedDict) console.debug(decodedDict) if (decodedDict == "") return ""; return JSON.parse(decodedDict) } /*$(document).mousedown(function(event){ if (!event.altKey) return; window.targetElement = $(event.target) var elmX = window.targetElement.offset().left var elmY = window.targetElement.offset().top window.targetElementOffsetX = elmX + (event.pageX - elmX) window.targetElementOffsetY = elmY + (event.pageY - elmY) return false }).mousemove(function(event){ if (!window.targetElement) return; var transX = event.pageX - window.targetElementOffsetX var transY = event.pageY - window.targetElementOffsetY var transStr = 'translate(' + transX + 'px, ' + transY + 'px)' window.targetElement.css('transform', transStr) return false }).mouseup(function(){ window.targetElement = null window.targetElementOffsetX = null window.targetElementOffsetY = null return false })*/ $('#fullScreenImage').on('show.bs.modal', function(event) { var $img = $(this).find("embed"); var imageUrl = new URL(dataRelatedTarget(event, 'src')); var dialogWidth = Number($(this).find('.modal-dialog').css('max-width').replace('px', '')); if (isNaN(dialogWidth)) { dialogWidth = 400 } var imageWidth = dialogWidth - 60; // Setting the image width to be the modal body with imageUrl.searchParams.append('w', imageWidth); $img.attr('type', $(event.relatedTarget).closest('.image-row').data('file-type')) $img.attr('src', imageUrl.href); if (dataRelatedTarget(event, 'extension') == '.pdf') return $(this).find('.modal-content').addClass('h-100') return $(this).find('.modal-content').removeClass('h-100') }); $('#fullScreenImage').on('shown.bs.modal', function(event) { var $img = $(this).find("img"); if ($img.width() / $img.height() > 1.3) return; $(this).find('.modal-dialog modal-lg').removeClass('modal-lg') }); $('#fullScreenImage').on('hidden.bs.modal', function(event) { $(this).find(".modal-dialog modal-lg").attr("class", "modal-dialog modal-lg modal-lg") }); $('#deleteImageSubmit').click(function(event) { var modal = $('#deleteImage') deleteDBItemRequest(modal).done(function(data) { removeImage($(`#image_${data.entry_id}`)); }) }); $('#defaultDeleteModal .submit').click(function(event) { var modal = $(this).closest('.modal') deleteDBItemRequest(modal).done(function(data) { $(`#${data.default_dom_id}`).slideRemove() }) }); function deleteDBItemRequest(modal=null, signedReqKw=null, flashSuccess=true, reqJson={}){ if (signedReqKw == null) signedReqKw = window.modalKwargs.signed_req_kw; return jsonAjax({ url: "/AJAX/delete_db_item", json: Object.assign({ signed_req_kw: signedReqKw, }, reqJson), modal: modal, catch_error: true, flashSuccess: flashSuccess }) } $('#deleteItem').on('show.bs.modal', function(event) { var $submitButton = $(this).find("#deleteItemSubmit"); $submitButton.data('ajax-url', dataRelatedTarget(event, 'ajax-url')); $submitButton.data('ajax-kwargs', dataRelatedTarget(event, 'ajax-kwargs')); $submitButton.data('table-row-id', dataRelatedTarget(event, 'table-row-id')); $submitButton.data('object-name', dataRelatedTarget(event, 'object-name')); }); $('#deleteItemSubmit').click(function(event) { var url = $(this).data('ajax-url') var kwargs = $(this).data('ajax-kwargs') var tableRowId = $(this).data('table-row-id') var objectName = $(this).data('object-name') $.post(url, kwargs).done(function(){ flash(objectName + " Deleted", "success") modal.modal('hide') removeTableRow($(`#buy_list_item_${data.buy_list_id}`)); }).fail(function() { flash_error("There was an error deleting the " + objectName + "."); }); }); $(function(){ $('.auto-resize').each(function(){ $(this).trigger('resize') }); }) $(document).on('input', '.auto-resize', function(){ $(this).trigger('resize') }); $(document).on('resize', '.auto-resize', function(){ if ($(this).val() == "") return; $(this).css('height', '') $(this).css('height', $(this)[0].scrollHeight + 2 + "px") }); function removeTableRow($tr) { var $tbody = $tr.closest('tbody'); var trAmount = $tbody.find('tr').length; if (trAmount == 1) { $tbody.append(`There's nothing here`); } $tr.remove(); return trAmount; } /* ---------- Notification center ---------- */ function modalBackdropHTML(htmlParams="", children=""){ return '' } function toggleTopMenu() { if ($(this).hasClass('shown')) { // notification center will be hidden // Hide the notification center $(this).slideUp().removeClass('shown') // Remove the backdrop $('body .hms-backdrop').removeClass('show') // After the backdrop is faded out, then remove it from the dom setTimeout(function(){ $('body .hms-backdrop').remove() }, 1000 * .15) return "hidden" } // Show the notification center $(this).slideDown().addClass('shown') // Append the backdrop to the body $(modalBackdropHTML()).appendTo('body') // Wait for the backdrop to be added, then add the show class setTimeout(function(){ $('.hms-backdrop').addClass('show') }, 10) return "shown" } function hideTopMenuOnDocClick(event) { var menuSelector = event.data.menuSelector if ($(menuSelector).is(":visible") && !(event.target).closest(menuSelector) && !$('.modal').hasClass('show')) { $(menuSelector).trigger('toggle'); } } $(document).click({menuSelector: '.notification-popover'}, hideTopMenuOnDocClick); $('#show-notification-center').click(function(event){ event.stopPropagation(); getNotifications({}, function(){ $('.notification-popover').trigger('toggle') }) }); $('.notification-popover').on('toggle', toggleTopMenu) function notificationButton(action, icon) { return ` ` } function notificationHTML(notification) { var buttons = [] console.debug(notification) if (notification['is_viewed']) { // buttons = notificationButton('dismiss', 'times') buttons = [notificationButton('delete', 'trash')] } else if (notification['is_dismissed']) { buttons = [notificationButton('restore', 'check'), notificationButton('delete', 'trash')] } return `
${ notification['Title'] }
${ notification['formatted_delivery_datetime'] }
${ notification['Content'] }
` } function notificationPlaceholderHTML(hidden=false) { return `
Looks like you're all caught up! You don't have any notifications.
` } function appendNotification(notificationHTMLString) { return $(notificationHTMLString).appendTo('.notification-popover .content-container') } $(document).on('click', '.notification .delete-notification', function(event){ var notification = $(this).closest('.notification') var signedReqKw = notification.data('signed-req-kw') clearNotification(signedReqKw).done(function(data){ notification.slideToggle(function(){ notification.remove() if ($('.notification-popover .content-container .notification').length != 0) return; appendNotification(notificationPlaceholderHTML(hidden=true)).slideDown() }) }) // prevent the link from being fired return false; }) // If there is no actionLink for the notification, then don't do anything $(document).on('click', '.notification', function(event){ if ($(this).attr('href') == 'null') return false }) function getNotifications(args, callback) { jsonAjax({ url: "/AJAX/get_notifications", json: {}, catch_error: true, default_error: 'There was an error getting your notifications.' }).done(function(data){ $('.notification-popover .content-container').empty(); for (var i=0; i 0) { // Keep the link from button from dragging the table row $(".DragDropUI a.btn").on('mousedown', function(event){ event.stopPropagation() }) $(function() { $('.DragDropUI').each(function(){ var handleSelector = $(this).data('handle-sel') if (!handleSelector) { handleSelector = null $(this).disableSelection(); } $(this).defaultSortable({ handle: handleSelector }) }) action = {} }); $(".DragDropUI").on("sortstart", function(event, ui) { var $parent = $(ui.item).parent(); action['draggable_item_name'] = $parent.data('draggable-item-name') || "tr" var rowExpression = action['draggable_item_name']; var index = $(ui.item).prevAll(rowExpression).length; action['table_name'] = $parent.data('table-name'); action['parent_list_id'] = $parent.attr('id'); action['parent_database_obj'] = $parent.data('parent-obj-name'); action['sorted_column'] = $parent.data('sorted-column'); action['order_column'] = $parent.data('order-column'); action['parent_obj_id'] = $parent.data('parent-obj-id'); action['start_index'] = index; action['obj_fingerprint'] = $parent.data('obj-fingerprint'); }).on("sortstop", function(event, ui) { var rowExpression = action['draggable_item_name']; var index = $(ui.item).prevAll(rowExpression).length; action['end_index'] = index; updateDragDropTable() }); function moveDragDropTr(startIndex, endIndex, parentListId) { startIndex ++ endIndex ++ var startTr = $(`#${parentListId} ${action['draggable_item_name']}:nth-of-type(${startIndex})`) var startTrHtml = startTr[0].outerHTML startTr.remove(); var endTr = $(`#${parentListId} ${action['draggable_item_name']}:nth-of-type(${endIndex})`); $(startTrHtml).insertBefore(endTr); } function updateDragDropTable() { if (action['start_index'] == action['end_index']) return ; console.debug('sending') console.debug(action) $.post("/AJAX/dragdrop_template", action).fail(function() { flash_error("There was an error moving your items."); moveDragDropTr(action['end_index'], action['start_index'], action['parent_list_id']); }); } } function not_null(variable, returned_val="", second_null=null) { if (variable == null || variable == second_null) { return returned_val } return variable } function is_touch_enabled() { return ( 'ontouchstart' in window ) || ( navigator.maxTouchPoints > 0 ) || ( navigator.msMaxTouchPoints > 0 ); } function hideSideMenu() { $('#sideBarMenu').parent().css('width', '100px') } $('.nav-tabs[role="tablist"] li.nav-item .nav-link[data-toggle="tab"]').click(function(){ var currentUrl = new URL(document.location); currentUrl.searchParams.set('activeTab', $(this).attr('href').replace('#', '')); window.history.replaceState("", "", currentUrl); }) $('.toggleTabs').click(function(){ var tabList = $(this).closest('[role="tablist"]') tabList.find('.nav-item.hidden-tab').toggleClass('d-flex'); $(this).find('.show, .hide').toggleClass('d-none') var currentUrl = new URL(document.location); var showHiddenTabs = ($(this).find('.show').hasClass('d-none')) ? tabList.attr('id') : false currentUrl.searchParams.set('showHiddenTabs', showHiddenTabs); window.history.replaceState("", "", currentUrl); }) $(function(){ $('.toggleTabs .hiddenCount').each(function(){ $(this).text($(this).closest('[role="tablist"]').find('.hidden-tab').length) }) }) function jsonAjax(args) { var ajaxArgs = Object.assign({ type: 'POST', contentType: "application/json; charset=utf-8", json: {}, complete: (jqXHR, textStatus) => { if (args.modal) args.modal.modal('hide'); if (!args.flashSuccess || textStatus != "success") return ; var successMessage = jqXHR.responseJSON.success if (!successMessage) return ; flash(successMessage) } }, args) ajaxArgs.data ??= JSON.stringify(ajaxArgs.json) // Equivalent to python's .setdefault() on dicts var ajaxBase = $.ajax(ajaxArgs) if (args.catch_error) { var default_error = (args.default_error) ? args.default_error : 'There was an unexpected error processing your request.' return ajaxBase.fail(function(response) { if (typeof response.responseJSON == 'undefined' || typeof response.responseJSON.error == 'undefined') { flash_error(default_error) } else { flash_error(response.responseJSON.error) } }); } return ajaxBase } function sendNotification(json) { jsonAjax({ "url": "/AJAX/create_notification", "json": json }).done(function(data){ var notificationLen = Number($('#notification-len').text().trim()) $('#notification-len').removeClass('d-none').text(notificationLen + 1) }) } function clearNotification(signedReqKw) { return deleteDBItemRequest(modal=null, signedReqKw=signedReqKw, flashSuccess=false).done(function(data) { getNotificationLen() }) } function getNotificationLen() { jsonAjax({ url: "/AJAX/get_notification_len", json: {} }).done(function(data){ var $notificationLen = $('#notification-len') if (data.new_notifications_len == 0) return $notificationLen.addClass('d-none'); $notificationLen.text(data.new_notifications_len).removeClass('d-none'); }) } $(document).on('click', '.dismiss-modal', function(){ $(this).closest('.modal').modal('hide') }) function ConvertFormToJSON(form){ var array = form.serializeArray(); var json = {}; $.each(array, function() { json[this.name] = this.value || ''; }); return json; } $(function(){ $('pre[data-toggle="textarea"]').each(function(){ var relatedTextarea = $(`
`) relatedTextarea.insertAfter(this) $(this).addClass('show') }) $('[data-toggle="input"]').each(function(){ $(this).addClass('view').html(` ${$(this).data('label')}: ${($(this).data('prefix')) ? $(this).data('prefix') : ""}${$(this).data('value')} ${($(this).data('suffix')) ? $(this).data('suffix') : ""} `) }) }) // Input Toggle JS $('[data-toggle="input"]').click(function(){ if ($(this).hasClass('edit')) return; if ($(this).closest('[data-input-group="true"]').trigger('edit')) return; $(this).trigger('edit') }) $(document).on('keyup', '[data-toggled="input"]', function(event){ if (event.key != "Escape") return; if ($(this).hasClass('view')) return; if ($(this).closest('[data-input-group="true"]').trigger('view')) return; $(this).closest('[data-toggle="input"]').trigger('view') }) $('[data-toggle="input"]').on('edit', function(event){ event.stopPropagation(); if ($(this).hasClass('edit')) return; $(this).trigger('toggle') $(this).find('.edit input').focus().val($(this).find('.view').text()) }) $('[data-toggle="input"]').on('view', function(event){ event.stopPropagation(); if ($(this).hasClass('view')) return; $(this).trigger('toggle') }) $('[data-toggle="input"]').on('toggle', function(){ $(this).toggleClass('edit view').find('.edit, .view').toggleClass('d-none') }) $('[data-toggle="input"]').on("save", function(event){ event.stopPropagation(); var value = $(this).find('.edit input').val(); $(this).find('.view').text(value) }) // Textarea Toggle JS $(document).on('keyup', '.textarea-edit-wrapper textarea', function(event){ if (event.key != "Escape") return; if ($(this).hasClass('view')) return; if ($(this).closest('[data-input-group="true"]').trigger('view')) return; $(this).parent().prev().trigger('view') }) $('pre[data-toggle="textarea"]:not([data-click="false"])').click(function(){ if ($(this).hasClass('edit')) return; if ($(this).closest('[data-input-group="true"]').trigger('edit')) return; $(this).trigger('edit'); }) $('pre[data-toggle="textarea"]').on("edit", function(event){ event.stopPropagation(); var content = $(this).text() var textareaWrapper = $(this).next(); var textarea = textareaWrapper.find('textarea'); $(this).trigger('toggle') textarea.focus().val(content).trigger('resize'); }) $('pre[data-toggle="textarea"]').on("view", function(event){ event.stopPropagation(); $(this).trigger('toggle') }) $('pre[data-toggle="textarea"]').on("toggle", function(event){ var that = this; var textareaWrapper = $(this).next(); textareaWrapper.toggleClass('d-none'); $(this).toggleClass('d-none'); setTimeout(function(){ textareaWrapper.toggleClass('show'); $(that).toggleClass('show') }, 5) }) $('pre[data-toggle="textarea"]').on("save", function(event){ event.stopPropagation(); var textarea = $(this).next().find('textarea'); $(this).text(textarea.val()) }) // Input Group Toggle $('[data-input-group="true"] button.reset').click(function(){ $(this).closest('[data-input-group="true"]').trigger('view') }) $('[data-input-group="true"] button.save').click(function(){ $(this).trigger('save') }) $('[data-input-group="true"]').on("edit view", function(event){ event.stopPropagation(); $(this).find('[data-toggle="textarea"], [data-toggle="input"]').trigger(event.type) $(this).find('.footer').toggleClass('d-none') }) // #save-button js $('#save-button').on('hms-show', function(){ if ($(this).hasClass('show')) return; $(this).animate({top: window.innerHeight - $(this).outerHeight(true) - $(this).outerHeight() + "px"}) $(this).animate({top: window.innerHeight - $(this).outerHeight(true) + "px"}, 200) $(this).addClass('show') }) $('#save-button').on('hms-hide', function(){ if (!$(this).hasClass('show')) return; $(this).animate({top: "100vh"}, 500) $(this).removeClass('show') }) $('.delete-ajax').click(function(){ $('#ajax-delete').modal('show', this) }) $('#ajax-delete').on('show.bs.modal', function(event){ var btn = event.relatedTarget window.modalRelatedTarget = btn; var itemType = $(btn).data('type') $(this).find('.hms-modal-header h3').text(`Delete ${itemType}`) $(this).find('.modal-body h5').text(` Are you sure you want to delete ${itemType}? `) }) $(".ajax").click(function(){ var btn = window.modalRelatedTarget || this var errorMessage = $(btn).data('error-message') var successMessage = $(btn).data('success-message') jsonAjax({ "url": $(btn).data('url'), "json": $(btn).data('json') }).done(function(data){ $('.modal').modal('hide') flash(successMessage || "data.success") $(`#${$(btn).data('remove-dom')}`).slideUp(300, function(){ $(this).remove() }) }).fail(function(response){ flash_error(errorMessage || response.responseJSON['error']) }) window.modalRelatedTarget = undefined }) function dbColToFieldName(colName) { var splitColName = colName.split(/(?=[A-Z])/); return splitColName.join('_').toLowerCase() } function fieldNameToDBCol(fieldName) { var splitFieldName = fieldName.split('_'); var splitColName = [] $.each(splitFieldName, function(){ splitColName.push(capitalize(this)) }) return splitColName.join('') } $.fn.setFormVals = function (item, fieldIds={}) { for (var key in item) { var fieldId = dbColToFieldName(key) var value = item[key]; var field = $(this).find(`#${fieldId}`); field.setFieldVal(value) } for (var fieldId in fieldIds) { var dbColName = fieldIds[fieldId]; var value = item[dbColName]; var field = $(this).find(`#${fieldId}`); field.setFieldVal(value) } return $(this) } $.fn.setFieldVal = function(value) { if ($(this).attr('type') == 'checkbox') { $(this).prop('checked', value) } else { $(this).val(value) } return $(this).trigger('change').trigger('input'); } $.fn.eachNotInArray = function (excludeIds, excludeCheckedFieldCheckboxes, func) { $(this).each(function(){ if (Boolean(excludeIds.find(obj => obj == this.id))) return; if ($(this).fieldCheckbox().prop('checked') == true) return; func(this) }) } $.fn.clearFormVals = function (defaultVals={}, excludeIds=[], excludeCheckedFieldCheckboxes) { $(this).find('input:not([type="checkbox"]), textarea').eachNotInArray(excludeIds, excludeCheckedFieldCheckboxes, function(field){ $(field).val("") }) $(this).find('input[type="checkbox"]:not(.field-checkbox)').eachNotInArray(excludeIds, excludeCheckedFieldCheckboxes, function(field){ $(field).prop('checked', false) }) $(this).find('select').eachNotInArray(excludeIds, excludeCheckedFieldCheckboxes, function(field){ // $(field).val('').trigger('change') $(field).find('option:first').prop('selected', true) if ($(field).hasClass('selectpicker')) { $(field).selectpicker('refresh') } }) for (var fieldId in defaultVals) { $(this).find(`#${fieldId}`).val(defaultVals[fieldId]).trigger('change').trigger('input') } return $(this) } $.fn.serializeJSON = function () { var json = {} var serializeArray = $(this).serializeArray() $.each(serializeArray, function(){ if (Number(this.value) || this.value == '0' || this.value == '0.00') { json[this.name] = Number(this.value) return } json[this.name] = this.value }) $(this).find('input:checkbox').each(function(){ json[this.name] = this.checked }); return json } $.fn.serializeJSONForDB = function (colNames={}, skipFields=['csrf_token', 'object_id']) { var json = {} var serializedJSON = $(this).serializeJSON() for (var key in serializedJSON) { if (skipFields.indexOf(key) != -1) continue; // If field in skip field object var value = serializedJSON[key] var colName = (colNames.hasOwnProperty(key)) ? colNames[key] : fieldNameToDBCol(key); json[colName] = value } return json } $.fn.fieldCheckbox = function () { return $('input[type="checkbox"]#' + $(this).attr('id') + '_checkbox') } $.fn.slideRemove = function (speed=300) { $(this).slideUp(speed, function(){ $(this).remove() }) } $.fn.defaultSortable = function (args) { var combinedArgs = Object.assign({ cancel: '.hms-cb, .btn', cursor: "grabbing", revert: 200, // Whether the sortable items should revert to their new positions using a smooth animation. zIndex: 998, containment: 'body', scroll: true, scrollSensitivity: 100, scrollSpeed: 75, zIndex: 9999 }, args) return $(this).sortable(combinedArgs) } $('.modal').on('shown.bs.modal', function(){ $(this).find('.auto-resize').trigger('resize') }) $(document).on('show.bs.modal', '.modal', function() { var zIndex = 1040 + 1 * $('.modal:visible').length; $(this).css('z-index', zIndex); setTimeout(() => $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack')); }); $('#reportIframeModal').on('show.bs.modal', function(event) { var reportIframeModalUrl = dataRelatedTarget(event, 'pdf-src'); $(this).find("iframe").attr('src', reportIframeModalUrl); $(this).find("#reportIframeModalDownload").attr('href', reportIframeModalUrl); var title = dataRelatedTarget(event, 'title'); $(this).find('#reportIframeModalLabel').text(title); $(this).find('iframe').attr("height", screen.height); }); let formatPhoneNumber = (str) => { //Filter only numbers from the input let cleaned = ('' + str).replace(/\D/g, ''); //Check if the input is of correct length let match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/); if (match) { return '(' + match[1] + ') ' + match[2] + '-' + match[3] }; return '' }; /* Focus the first input on modal show */ $('.modal:not([data-input-focus="false"])').on('shown.bs.modal', function (event) { var textInputs = $(this).find('input:text') if (textInputs.length == 0) return; textInputs[0].focus() }) /* Depreciated */ $('.modal').on('show.bs.modal', function (event) { if (!event.relatedTarget || !dataRelatedTarget(event, 'id')) return; $(this).find('.submit').data('id', dataRelatedTarget(event, 'id')) }) $.fn.slideToggleBool = function(bool, options) { return bool? $(this).slideDown(options) : $(this).slideUp(options); } /* ---------- Images ---------- */ $('#uploadImage').on('hide.bs.modal', function(e){ $('.image-input-container').slideUp(300, function(){ $(this).addClass('h-0').show() $('#profile-img-tag')[0].src = ""; }); }) $('#uploadImageForm').submit(function(event){ event.preventDefault(); var form = $(this)[0] var formData = new FormData(form) // Clear the non resized images from the form data formData.delete('files') // Add the resized images back in $.each(window.resizedFiles, function(){ formData.append("files", this) }) flash('Images are uploading, refreshing the page will result in images not saving.', 'warning') $(this).find('.modal').modal('hide') window.uploadingImages = true jsonAjax({ type: "POST", url: "/upload_image", data: formData, processData: false, contentType: false, catch_error: true, default_error: "There was an error uploading your image." }).done(function(data){ window.uploadingImages = false flash(data.success, "success", 20); var imageContainer = $(`#${formData.get('image_location')}_${formData.get('image_type_id')}`) imageContainer.trigger('reloadImages') }).fail(function(){ window.uploadingImages = false }); }) $(window).on('beforeunload', function(){ // If there are images uploading then show a warning not to reload the page if (window.uploadingImages) { return false } }) $('#uploadImageForm input#profile-img').change(function(){ var maxImageSize = { width: 1920, // maximum width height: 1920 // maximum height } $('.image-input-container').removeClass('h-0'); window.resizedFiles = [] $.each(this.files, function(){ var file = this; ImageTools.resize(file, maxImageSize, function(blob, didItResize) { $('#profile-img-tag')[0].src = window.URL.createObjectURL(blob); // If it didn't get resized then just add it to the list if (!didItResize) { return window.resizedFiles.push(blob) } // If the image got resized then convert it from a blob to a file obj and add it to the list var resizedFileObj = new File([blob], file.name, { type: file.type }) window.resizedFiles.push(resizedFileObj) }); }) }) $(document).on('click', '.refreshImages', function(){ $(this).closest('.image-container-wrapper').trigger('reloadImages') }) $(document).on('reloadImages', '.image-container-wrapper', function(event){ var itemId = $(this).data('item-id') var tableName = $(this).data('table-name') jsonAjax({ url: "/AJAX/get_images_html", json: { item_id: itemId, table_name: tableName, header: $(this).find('h4').text() // Get the text from the current header }, catch_error: true }).done(function(data){ $(`#${tableName}_${itemId}`).slideUp(200, function(){ $(data.image_html).replaceAll(this).hide().slideDown(200) $('embed[lazy]').trigger('load-file') }) flash('Images reloaded!') }) return false }) function htmlEncode(string) { return String(string).replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/\//, '/'); } function removeBlankLinesHTML(string) { return String(string).replace(/>[' ', '\n']*<") } $(function(){ $('embed[lazy]').trigger('load-file') }) $(document).on('load-file', 'embed[lazy]', function(){ $(this).attr('src', $(this).attr('lazy')) }) /* ---------- Spotlight item ---------- */ function randomInt(len=8) { return Math.random().toString().substr(2, len) } function showBackdrop() { if ($('.hms-backdrop').length != 0) return $(this) // If there already is a hms-backdrop // Prepend the backdrop to the body $(modalBackdropHTML()).prependTo('body') // Wait 10ms for the backdrop to be added, then add the show class return wait(10).then(function(){ $('.hms-backdrop').addClass('show') }) } function hideBackdrop() { // Remove the backdrop $('body .hms-backdrop').removeClass('show') // After the backdrop is faded out, then remove it from the dom return wait(1000 * .15).then(function(){ $('body .hms-backdrop').remove() }) } $.fn.spotlight = function () { $(this).addClass('spotlight') return showBackdrop() // Show the .hms-backdrop, and return the Promise } $.fn.unSpotlight = function () { $(this).removeClass('spotlight') return hideBackdrop() } function toggleTopMenu() { if ($(this).hasClass('shown')) { // notification center will be hidden // Hide the notification center $(this).slideUp().removeClass('shown') return hideBackdrop() // Hide the backdrop and return the Promise } // Show the notification center $(this).slideDown().addClass('shown') return showBackdrop() // Show the backdrop and return the Promise } /* ---------- Page Tour ---------- */ $('.hms-tooltip').on('initSpotlight', function(){ var that = $(this) var spotlightElem = !(String(that.data('spotlight')) == "false") var celebrateEnd = !(String(that.data('celebrate-end')) == "false") // Scroll to element that.scrollToTargetAdjusted() // Show tooltip, and spotlight element var ttElm = that if (that.data('tt-child')) { var ttElm = that.find(that.data('tt-child')) } ttElm.addClass('show-tt') if (spotlightElem) { that.spotlight() } // Get the close-on event var eventType = that.data('close-on'); console.debug(eventType) function continueTour(){ if (eventType) that.trigger('tourCloseOn'); // Trigger the event "tourClick" if there is a close-on event // Reset the elements clickableness to the default that.css('pointer-events', '') // In the callback hide the tooltip and un spotlight the element return ttElm.removeClass('show-tt').unSpotlight().then(function(){ // In the Callback trigger the next elements initSpotlight event var triggerNext = $(that.data('trigger-next')) if (triggerNext.length == 0) { if (!celebrateEnd) return; // If celebrate end if off, then don't celebrate return finishTour() } else if (!triggerNext.is(':visible')) { return that.trigger('initSpotlight') } triggerNext.trigger('initSpotlight') }) } if (!eventType || eventType == 'doc') { $(document).one('click', continueTour) // If there isn't a close-on event, then make the element not clickable that.css('pointer-events', 'none') return false } // Set handler for said event ttElm.one(eventType, continueTour) return false }) function startTour(tourNum) { $(`.tour_${tourNum}_1`).trigger('initSpotlight') } $('.startTour').click(function(e){ e.preventDefault() window.localStorage.setItem('tourNum', $(this).data('tour-num')) window.location.href = window.location.href.split('?')[0] }) function confettiBottomCorners() { var baseOptions = { particleCount: 100, spread: 75, startVelocity: 70, zIndex: 1042, ticks: 200 } confetti(Object.assign(baseOptions, { angle: 45, origin: { y: 1, x: 0 }, })) return confetti(Object.assign(baseOptions, { angle: 135, origin: { y: 1, x: 1 }, })) } /*function finishTour() { showBackdrop(children=`
Congratulations,
You finished the Tour!!!
`).then(function(){ // Show the backdrop confettiBottomCorners().then(function(){ // Once the backdrop is shown, then launch the confetti hideBackdrop() // After the confetti is gone, then hide the backdrop }) }) }*/ function finishTour() { flash('You completed the Page Tour') confettiBottomCorners() // Launch the confetti wait(400).then(confettiBottomCorners) } function setIntervalX(callback, delay, repetitions) { var x = 0; var intervalID = window.setInterval(function () { callback(); if (++x === repetitions) { window.clearInterval(intervalID); } }, delay); } $.fn.scrollToTargetAdjusted = function (){ var headerOffset = 200; var offsetPosition = $(this).offset().top - headerOffset; window.scrollTo({top: offsetPosition}); } /* ---------- Dynamic Dropdown JS ---------- */ $(".dynamicDropdown").change(function(){ var select = this var url = $(select).data('url') $.post(url, {"obj_id": $(this).val()}).done(function(data) { var optionHTML = [] var list = Object.values(data)[0] $.each(list, function() { optionHTML.push(``) }) var nextSelectSelector = $(select).data('next-select') $(nextSelectSelector).html(optionHTML.join('')).change() if ($(nextSelectSelector).hasClass('selectpicker')) { $(nextSelectSelector).selectpicker('refresh') } }).fail(function() { flash_error("There was an error changing the dynamic dropdowns."); }); }) /* ---------- setTimeout with a Promise ---------- */ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); setInterval(getNotificationLen, 180000); // get new notification count every 3 minutes