$(document).ready(function() { // open filter modal if corresponding anchor is in url (originating from hotkeys.js) if(window.location.href.endsWith('#modalFilter')) { $('#modalFilter').modal('open'); } if($("#transaction-name").length) { let elements = document.querySelectorAll('#transaction-name'); let autoCompleteInstances = M.Autocomplete.init(elements, { data: transactionNameSuggestions, }); // prevent tab traversal for dropdown (otherwise "tab" needs to be hit twice to jump from name input to amount input) autoCompleteInstances[0].dropdown.dropdownEl.tabIndex = -1; document.getElementById('transaction-name').focus(); } if($("#transaction-description").length) { $("#transaction-description").characterCounter(); } if($(".datepicker-simple".length) && $("#transaction-repeating-end-date-input").length) { let pickerEndDate = document.getElementById('transaction-repeating-end-date-input'); // select corresponding radio button let endDate = document.getElementById("repeating-end-date"); pickerEndDate.addEventListener('input', function() { endDate.checked = true; }); pickerEndDate.addEventListener('focus', function() { endDate.checked = true; }); } if($(".datepicker").length) { let pickerStartDate = M.Datepicker.init(document.getElementById('transaction-datepicker'), { yearRange: 25, firstDay: 1, showClearBtn: false, setDefaultDate: true, defaultDate: startDate, i18n: { // Strings and translations months: monthNames, monthsShort: monthNamesShort, weekdays: weekDays, weekdaysShort: weekDaysShort, weekdaysAbbrev: weekDaysLetters, // Buttons cancel: buttonCancel, done: buttonClose, // Accessibility labels labelMonthNext: '>', labelMonthPrev: '<' }, // Formats format: 'dd.mm.yyyy', formatSubmit: 'dd.mm.yyyy', onSelect: function() { if(typeof pickerEndDate !== "undefined") { pickerEndDate.destroy(); pickerEndDate = createDatePickerEnd(this.date, pickerEndDate.date); } } }); // picker end date if(typeof endDate !== "undefined") { let pickerEndDate = createDatePickerEnd(pickerStartDate.date, endDate); } } function createDatePickerEnd(minDate, selectedDate) { if(selectedDate < minDate) { selectedDate = minDate; } return M.Datepicker.init(document.getElementById('transaction-repeating-end-date-input'), { yearRange: 50, firstDay: 1, showClearBtn: false, setDefaultDate: true, minDate: minDate, defaultDate: selectedDate, i18n: { // Strings and translations months: monthNames, monthsShort: monthNamesShort, weekdays: weekDays, weekdaysShort: weekDaysShort, weekdaysAbbrev: weekDaysLetters, // Buttons done: buttonClose, // Accessibility labels labelMonthNext: '>', labelMonthPrev: '<' }, // Formats format: 'dd.mm.yyyy', formatSubmit: 'dd.mm.yyyy', onSelect: function() { // select corresponding radio button let endDate = document.getElementById("repeating-end-date"); endDate.checked = true; } }); } if($('#transaction-amount').length) { $('#transaction-amount').on('change keydown paste input', function() { validateAmount($(this).val()); }); } if($(transactionRepeatingModifierID).length) { $(transactionRepeatingModifierID).on('change keydown paste input', function() { // substr(1) removes "#" at the beginning validateNumber($(this).val(), transactionRepeatingModifierID.substr(1), "hidden-" + transactionRepeatingModifierID.substr(1), numberValidationMessage, REGEX_NUMBER); }); } if($(transactionRepeatingEndAfterXTimesInputID).length) { $(transactionRepeatingEndAfterXTimesInputID).on('change keydown paste input', function() { validateNumber($(this).val(), transactionRepeatingEndAfterXTimesInputID.substr(1), null, numberValidationMessage, REGEX_NUMBER); // select corresponding radio button let endAfterXTimes = document.getElementById("repeating-end-after-x-times"); endAfterXTimes.checked = true; }); } if($(".chips-autocomplete").length) { let elements = document.querySelectorAll('.chips-autocomplete'); let instances = M.Chips.init(elements, { autocompleteOptions: { data: tagAutoComplete, limit: Infinity, minLength: 1 }, placeholder: tagsPlaceholder, secondaryPlaceholder: tagsPlaceholder, data: initialTags }); // prevent tab traversal for dropdown (otherwise "tab" needs to be hit twice to jump from tag input to account input) instances[0].autocomplete.dropdown.dropdownEl.tabIndex = -1; } // prevent form submit on enter (otherwise tag functionality will be hard to use) $(document).on("keypress", 'form', function(e) { if(e.ctrlKey) { return true; } let code = e.keyCode || e.which; if(code === 13) { if(e.target.nodeName === 'TEXTAREA' || e.target.id === 'search') { return true; } e.preventDefault(); return false; } }); $('.buttonIncome').click(function() { $('.buttonIncome').each(function() { $(this).removeClass("background-grey"); $(this).removeClass("text-isPayment"); $(this).addClass("background-green"); }); $('.buttonExpenditure').each(function() { $(this).removeClass("background-red"); $(this).addClass("background-grey"); $(this).addClass("text-isPayment"); }); document.getElementById("input-isPayment").value = 0; }); $('.buttonExpenditure').click(function() { $('.buttonExpenditure').each(function() { $(this).removeClass("background-grey"); $(this).removeClass("text-isPayment"); $(this).addClass("background-red"); }); $('.buttonIncome').each(function() { $(this).removeClass("background-green"); $(this).addClass("background-grey"); $(this).addClass("text-isPayment"); }); document.getElementById("input-isPayment").value = 1; }); M.FloatingActionButton.init(document.querySelectorAll('.new-transaction-button'), { direction: 'bottom', hoverEnabled: false }); // scroll to highlighted transaction let highlightedSmall = document.getElementById("highlighted-small"); let highlightedLarge = document.getElementById("highlighted-large"); if(highlightedSmall !== undefined && highlightedSmall != null && !isHidden(highlightedSmall)) { $('html, body').animate({ scrollTop: $(highlightedSmall).offset().top }, 500); } else if(highlightedLarge !== undefined && highlightedLarge != null && !isHidden(highlightedLarge)) { $('html, body').animate({ scrollTop: $(highlightedLarge).offset().top }, 500); } $('.button-request-delete-transaction').click(function() { fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function() { }); }); $('#button-transaction-add-repeating-option').click(function() { toggleRepeatingOptions(true); }); $('#button-transaction-remove-repeating-option').click(function() { toggleRepeatingOptions(false); }); }); function toggleRepeatingOptions(show) { document.getElementById('button-transaction-add-repeating-option').classList.toggle('hidden', show); document.getElementsByName('isRepeating')[0].value = show; document.getElementById('transaction-repeating-option').classList.toggle('hidden', !show); document.getElementById('button-transaction-remove-repeating-option').classList.toggle('hidden', !show); } function isHidden(el) { let style = window.getComputedStyle(el); return (style.display === 'none' || style.display === 'none !important') } let transactionRepeatingModifierID = "#transaction-repeating-modifier"; let transactionRepeatingEndAfterXTimesInputID = "#transaction-repeating-end-after-x-times-input"; AMOUNT_REGEX = new RegExp("^-?\\d+(,\\d+)?(\\.\\d+)?$"); ALLOWED_CHARACTERS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", "."]; DATE_REGEX_SHORT_NO_DOTS = new RegExp("^\\d{6}$"); DATE_REGEX_LONG_NO_DOTS = new RegExp("^\\d{8}$"); DATE_REGEX_SHORT = new RegExp("^(\\d{2}.\\d{2}.)(\\d{2})$"); DATE_REGEX_LONG = new RegExp("^\\d{2}.\\d{2}.\\d{4}$"); function validateAmount(text, allowEmpty = false) { let id = "transaction-amount"; if(allowEmpty && text.length === 0) { removeTooltip(id); document.getElementById("hidden-" + id).value = ""; return true; } if(text.match(AMOUNT_REGEX) == null) { addTooltip(id, amountValidationMessage); document.getElementById("hidden-" + id).value = ""; return false; } else { removeTooltip(id); let amount = parseFloat(text.replace(",", ".")) * 100; document.getElementById("hidden-" + id).value = amount.toFixed(0); return true; } } function validateDate(inputId) { let dateInput = document.getElementById(inputId); dateInput.value = dateInput.value.trim(); let date = dateInput.value; date = convertDateWithoutDots(date); dateInput.value = date; if(date.match(DATE_REGEX_LONG) != null) { removeTooltip(inputId); return true; } let match = date.match(DATE_REGEX_SHORT); if(match != null) { let dayAndMonth = match[1]; let year = match[2]; let currentYear = new Date().getFullYear(); currentYear = currentYear.toString().substr(0, 2); dateInput.value = dayAndMonth + currentYear + year; removeTooltip(inputId); return true; } else { addTooltip(inputId, dateValidationMessage); return false; } } function convertDateWithoutDots(dateString) { let yearLength = 2; if(dateString.match(DATE_REGEX_SHORT_NO_DOTS) != null) { yearLength = 2; } else if(dateString.match(DATE_REGEX_LONG_NO_DOTS) != null) { yearLength = 4; } else { return dateString; } return dateString.substr(0, 2) + '.' + dateString.substr(2, 2) + '.' + dateString.substr(4, yearLength); } function validateForm(isSaveAndContinue = false, allowEmptyAmount = false, skipKeywordCheck = false) { // name (keyword check) let isExpenditureSwitch = document.getElementById('input-isPayment'); let isExpenditure = isExpenditureSwitch !== null && (isExpenditureSwitch.value === "1" || isExpenditureSwitch.value === "true"); if(!skipKeywordCheck && isExpenditure) { let nameContainsKeywords = checkNameForKeywords(isSaveAndContinue); if(nameContainsKeywords) { return false; } } // amount let isValidAmount = validateAmount($('#transaction-amount').val(), allowEmptyAmount); if(!isValidAmount) { return false; } // start date let datePickerId = 'transaction-datepicker'; if(document.getElementById(datePickerId) !== null) { let isValidDate = validateDate(datePickerId); if(!isValidDate) { return false; } } // description let description = document.getElementById('transaction-description').value; if(description.length > 250) { return false; } // handle tags if($(".chips-autocomplete").length) { let tags = M.Chips.getInstance(document.querySelector('.chips-autocomplete')).chipsData; let parent = document.getElementById("hidden-transaction-tags"); for(let i = 0; i < tags.length; i++) { let input = document.createElement("input"); input.setAttribute("type", "hidden"); input.setAttribute("name", "tags[" + i + "].name"); input.setAttribute("value", tags[i].tag); parent.appendChild(input); } } if(document.getElementsByName('isRepeating')[0].value === "true") { if(!validateNumber($(transactionRepeatingModifierID).val(), transactionRepeatingModifierID.substr(1), "hidden-" + transactionRepeatingModifierID.substr(1), numberValidationMessage, REGEX_NUMBER)) { return false; } // handle repeating end let endNever = document.getElementById("repeating-end-never"); let endAfterXTimes = document.getElementById("repeating-end-after-x-times"); let endDate = document.getElementById("repeating-end-date"); let endInput = document.getElementById("hidden-transaction-repeating-end-value"); if(endNever.checked) { return true; } if(endAfterXTimes.checked) { if(!validateNumber($(transactionRepeatingEndAfterXTimesInputID).val(), transactionRepeatingEndAfterXTimesInputID.substr(1), null, numberValidationMessage, REGEX_NUMBER)) { return false; } endInput.value = $(transactionRepeatingEndAfterXTimesInputID).val(); } if(endDate.checked) { // start date let isValidDate = validateDate('transaction-repeating-end-date-input'); if(!isValidDate) { return false; } endInput.value = $("#transaction-repeating-end-date-input").val(); } } return true; } function checkNameForKeywords(isSaveAndContinue) { let url = document.getElementById('keywordCheckUrl').dataset.url; let transactionName = document.getElementById('transaction-name').value; let result; $.ajax({ async: false, type: 'GET', url: url + '?transactionName=' + transactionName, data: {}, success: function(data, textStatus, request) { if(request.status === 200) { // name contains at least one keyword result = true; openKeywordWarningModal(data, isSaveAndContinue); } else { result = false; } }, error: function(data) { console.error(data); } }); return result; } function openKeywordWarningModal(htmlData, isSaveAndContinue) { let modalID = '#modalTransactionNameKeywordWarning'; $('#transactionNameKeywordWarningModalContainer').html(htmlData); $(modalID).modal(); $(modalID).modal('open'); // button ignore $('#keyword-warning-button-ignore').click(function() { $(modalID).modal('close'); let button; if(isSaveAndContinue) { button = document.getElementById('button-save-transaction-and-continue'); } else { button = document.getElementById('button-save-transaction'); } let allowEmptyAmount = document.getElementById('template-name') !== null; // rebind onclick function of button to skip keyword check once button.onclick = function() { return validateForm(isSaveAndContinue, allowEmptyAmount, true); }; button.click(); // reset onsubmit function of button in case user edits transaction name too after fixing validation errors button.onclick = function() { return validateForm(isSaveAndContinue, allowEmptyAmount, false); }; }); }