function successToast(message) { Swal.fire({ toast: true, position: "top-end", showConfirmButton: false, timer: 3000, title: message, timerProgressBar: true, icon: "success", didOpen: (toast) => { toast.onmouseenter = Swal.stopTimer; toast.onmouseleave = Swal.resumeTimer; } }) } function errorToast(message) { Swal.fire({ toast: true, position: "top-end", showConfirmButton: false, timer: 3000, title: message, timerProgressBar: true, icon: "error", didOpen: (toast) => { toast.onmouseenter = Swal.stopTimer; toast.onmouseleave = Swal.resumeTimer; } }) } function viewVehicle(vehicleId) { window.location.href = `/Vehicle/Index?vehicleId=${vehicleId}`; } function saveVehicle(isEdit) { var vehicleId = getVehicleModelData().id; var vehicleYear = $("#inputYear").val(); var vehicleMake = $("#inputMake").val(); var vehicleModel = $("#inputModel").val(); var vehicleTags = $("#inputTag").val(); var vehiclePurchaseDate = $("#inputPurchaseDate").val(); var vehicleSoldDate = $("#inputSoldDate").val(); var vehicleLicensePlate = $("#inputLicensePlate").val(); var vehicleIsElectric = $("#inputFuelType").val() == 'Electric'; var vehicleIsDiesel = $("#inputFuelType").val() == 'Diesel'; var vehicleUseHours = $("#inputUseHours").is(":checked"); var vehicleOdometerOptional = $("#inputOdometerOptional").is(":checked"); var vehicleHasOdometerAdjustment = $("#inputHasOdometerAdjustment").is(':checked'); var vehicleOdometerMultiplier = $("#inputOdometerMultiplier").val(); var vehicleOdometerDifference = parseInt(globalParseFloat($("#inputOdometerDifference").val())).toString(); var vehiclePurchasePrice = $("#inputPurchasePrice").val(); var vehicleSoldPrice = $("#inputSoldPrice").val(); var vehicleIdentifier = $("#inputIdentifier").val(); var vehicleDashboardMetrics = $("#collapseMetricInfo :checked").map(function () { return this.value; }).toArray(); var extraFields = getAndValidateExtraFields(); //validate var hasError = false; if (extraFields.hasError) { hasError = true; } if (vehicleYear.trim() == '' || parseInt(vehicleYear) < 1900) { hasError = true; $("#inputYear").addClass("is-invalid"); } else { $("#inputYear").removeClass("is-invalid"); } if (vehicleMake.trim() == '') { hasError = true; $("#inputMake").addClass("is-invalid"); } else { $("#inputMake").removeClass("is-invalid"); } if (vehicleModel.trim() == '') { hasError = true; $("#inputModel").addClass("is-invalid"); } else { $("#inputModel").removeClass("is-invalid"); } if (vehicleIdentifier == "LicensePlate") { if (vehicleLicensePlate.trim() == '') { hasError = true; $("#inputLicensePlate").addClass("is-invalid"); } else { $("#inputLicensePlate").removeClass("is-invalid"); } } else { $("#inputLicensePlate").removeClass("is-invalid"); //check if extra fields have value. var vehicleIdentifierExtraField = extraFields.extraFields.filter(x => x.name == vehicleIdentifier); //check if extra field exists. if (vehicleIdentifierExtraField.length == 0) { $(".modal.fade.show").find(`.extra-field [placeholder='${vehicleIdentifier}']`).addClass("is-invalid"); hasError = true; } else { $(".modal.fade.show").find(`.extra-field [placeholder='${vehicleIdentifier}']`).removeClass("is-invalid"); } } if (vehicleHasOdometerAdjustment) { //validate odometer adjustments //validate multiplier if (vehicleOdometerMultiplier.trim() == '' || !isValidMoney(vehicleOdometerMultiplier)) { hasError = true; $("#inputOdometerMultiplier").addClass("is-invalid"); } else { $("#inputOdometerMultiplier").removeClass("is-invalid"); } //validate difference if (vehicleOdometerDifference.trim() == '' || isNaN(vehicleOdometerDifference)) { hasError = true; $("#inputOdometerDifference").addClass("is-invalid"); } else { $("#inputOdometerDifference").removeClass("is-invalid"); } } if (vehiclePurchasePrice.trim() != '' && !isValidMoney(vehiclePurchasePrice)) { hasError = true; $("#inputPurchasePrice").addClass("is-invalid"); $("#collapsePurchaseInfo").collapse('show'); } else { $("#inputPurchasePrice").removeClass("is-invalid"); } if (vehicleSoldPrice.trim() != '' && !isValidMoney(vehicleSoldPrice)) { hasError = true; $("#inputSoldPrice").addClass("is-invalid"); $("#collapsePurchaseInfo").collapse('show'); } else { $("#inputSoldPrice").removeClass("is-invalid"); } if (hasError) { return; } $.post('/Vehicle/SaveVehicle', { id: vehicleId, imageLocation: uploadedFile, year: vehicleYear, make: vehicleMake, model: vehicleModel, licensePlate: vehicleLicensePlate, isElectric: vehicleIsElectric, isDiesel: vehicleIsDiesel, tags: vehicleTags, useHours: vehicleUseHours, extraFields: extraFields.extraFields, purchaseDate: vehiclePurchaseDate, soldDate: vehicleSoldDate, odometerOptional: vehicleOdometerOptional, hasOdometerAdjustment: vehicleHasOdometerAdjustment, odometerMultiplier: vehicleOdometerMultiplier, odometerDifference: vehicleOdometerDifference, purchasePrice: vehiclePurchasePrice, soldPrice: vehicleSoldPrice, dashboardMetrics: vehicleDashboardMetrics, vehicleIdentifier: vehicleIdentifier }, function (data) { if (data) { if (!isEdit) { successToast("Vehicle Added"); hideAddVehicleModal(); loadGarage(); } else { successToast("Vehicle Updated"); hideEditVehicleModal(); viewVehicle(vehicleId); } } else { errorToast(genericErrorMessage()); } }); } function toggleOdometerAdjustment() { var isChecked = $("#inputHasOdometerAdjustment").is(':checked'); if (isChecked) { $("#odometerAdjustments").collapse('show'); } else { $("#odometerAdjustments").collapse('hide'); } } function uploadThumbnail(event) { var originalImage = event.files[0]; var maxHeight = 290; try { //load image and perform Hermite resize var img = new Image(); img.onload = function () { URL.revokeObjectURL(img.src); var imgWidth = img.width; var imgHeight = img.height; if (imgHeight > maxHeight) { //only scale if height is greater than threshold var imgScale = maxHeight / imgHeight; var newImgWidth = imgWidth * imgScale; var newImgHeight = imgHeight * imgScale; var resizedCanvas = hermiteResize(img, newImgWidth, newImgHeight); resizedCanvas.toBlob((blob) => { let file = new File([blob], originalImage.name, { type: "image/jpeg" }); uploadFileAsync(file); }, 'image/jpeg'); } else { uploadFileAsync(originalImage); } } img.src = URL.createObjectURL(originalImage); } catch (error) { console.log(`Error while attempting to upload and resize thumbnail - ${error}`); uploadFileAsync(originalImage); } } //Resize method using Hermite interpolation //JS implementation by viliusle function hermiteResize(origImg, width, height) { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); canvas.width = origImg.width; canvas.height = origImg.height; ctx.drawImage(origImg, 0, 0); var width_source = canvas.width; var height_source = canvas.height; width = Math.round(width); height = Math.round(height); var ratio_w = width_source / width; var ratio_h = height_source / height; var ratio_w_half = Math.ceil(ratio_w / 2); var ratio_h_half = Math.ceil(ratio_h / 2); var img = ctx.getImageData(0, 0, width_source, height_source); var img2 = ctx.createImageData(width, height); var data = img.data; var data2 = img2.data; for (var j = 0; j < height; j++) { for (var i = 0; i < width; i++) { var x2 = (i + j * width) * 4; var weight = 0; var weights = 0; var weights_alpha = 0; var gx_r = 0; var gx_g = 0; var gx_b = 0; var gx_a = 0; var center_y = (j + 0.5) * ratio_h; var yy_start = Math.floor(j * ratio_h); var yy_stop = Math.ceil((j + 1) * ratio_h); for (var yy = yy_start; yy < yy_stop; yy++) { var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half; var center_x = (i + 0.5) * ratio_w; var w0 = dy * dy; //pre-calc part of w var xx_start = Math.floor(i * ratio_w); var xx_stop = Math.ceil((i + 1) * ratio_w); for (var xx = xx_start; xx < xx_stop; xx++) { var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half; var w = Math.sqrt(w0 + dx * dx); if (w >= 1) { //pixel too far continue; } //hermite filter weight = 2 * w * w * w - 3 * w * w + 1; var pos_x = 4 * (xx + yy * width_source); //alpha gx_a += weight * data[pos_x + 3]; weights_alpha += weight; //colors if (data[pos_x + 3] < 255) weight = weight * data[pos_x + 3] / 250; gx_r += weight * data[pos_x]; gx_g += weight * data[pos_x + 1]; gx_b += weight * data[pos_x + 2]; weights += weight; } } data2[x2] = gx_r / weights; data2[x2 + 1] = gx_g / weights; data2[x2 + 2] = gx_b / weights; data2[x2 + 3] = gx_a / weights_alpha; } } //clear and resize canvas canvas.width = width; canvas.height = height; ctx.clearRect(0, 0, width, height); //draw ctx.putImageData(img2, 0, 0); return canvas; } function uploadFileAsync(event) { let formData = new FormData(); if (event.files != undefined && event.files.length > 0) { formData.append("file", event.files[0]); } else { formData.append("file", event); } sloader.show(); $.ajax({ url: "/Files/HandleFileUpload", data: formData, cache: false, processData: false, contentType: false, type: 'POST', success: function (response) { sloader.hide(); if (response.trim() != '') { uploadedFile = response; } }, error: function () { sloader.hide(); errorToast("An error has occurred, please check the file size and try again later.") } }); } function isValidMoney(input) { const euRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((\.\d{3}){0,8}|(\d{3}){0,8})(,\d{1,3}?)?\)?$/; const usRegex = /^\$?(?=\(.*\)|[^()]*$)\(?\d{1,3}((,\d{3}){0,8}|(\d{3}){0,8})(\.\d{1,3}?)?\)?$/; return (euRegex.test(input) || usRegex.test(input)); } function initDatePicker(input, futureOnly) { if (futureOnly) { input.datepicker({ startDate: "+0d", format: getShortDatePattern().pattern, autoclose: true, weekStart: getGlobalConfig().firstDayOfWeek }); } else { input.datepicker({ endDate: "+0d", format: getShortDatePattern().pattern, autoclose: true, weekStart: getGlobalConfig().firstDayOfWeek }); } } function initTagSelector(input, noDataList) { if (noDataList) { input.tagsinput({ useDataList: false }); } else { input.tagsinput(); } } function showMobileNav() { $(".lubelogger-mobile-nav").addClass("lubelogger-mobile-nav-show"); } function hideMobileNav() { $(".lubelogger-mobile-nav").removeClass("lubelogger-mobile-nav-show"); } function bindWindowResize() { $(window).on('resize', function () { hideMobileNav(); }); } function encodeHTMLInput(input) { const encoded = document.createElement('div'); encoded.innerText = input; return encoded.innerHTML; } function decodeHTMLEntities(text) { return $("