UNPKG

csdsolutions-csdjs

Version:

Libreria per i progetti di CSD Solutions

449 lines (375 loc) 15.3 kB
// Funzione per inizializzare gli input number function initializeNumber(inputElement) { const $input = $CSD(inputElement); // Store the original val method const originalVal = $input.val.bind($input); // Override val method for this specific input $input.val = function(value) { if (arguments.length === 0) { // Getter const rawValue = $input.data("rawValue"); if (rawValue) { return stripCurrency(rawValue, $input).replace(",", "."); } const currentValue = originalVal(); return stripCurrency(currentValue, $input).replace(",", "."); } else { // Setter if (value !== "") { const rawValue = formatNumber( $input, value.toString().replace(".", ",") ); $input.data("rawValue", rawValue); const formattedValue = buildFormattedValue($input, rawValue); return originalVal(formattedValue); } else { $input.data("rawValue", ""); return originalVal(""); } } }; // Aggiungi le frecce per incremento e decremento const $arrows = $CSD(` <div class="csd-input-arrows"> <button type="button" class="csd-arrow-btn up"><ion-icon name="chevron-up-outline"></ion-icon></button> <button type="button" class="csd-arrow-btn down"><ion-icon name="chevron-down-outline"></ion-icon></button> </div> `); // Imposto il posizionamento relativo per il contenitore delle frecce $input.css("position", "relative"); $input.after($arrows); // Converto l'input in tipo testo per gestire la virgola $input.attr("type", "text"); // Funzioni per recuperare dinamicamente le configurazioni function getCurrencySymbol($el) { return $el.attr("currency") || ""; } function getFixedDecimals($el) { return $el.attr("decimal") !== undefined ? parseInt($el.attr("decimal")) : 0; } function getStep($el) { return $el.attr("step") ? $el.attr("step") : 1; } function getMinVal($el) { return $el.attr("min") !== undefined ? parseFloat($el.attr("min")) : null; } function getMaxVal($el) { return $el.attr("max") !== undefined ? parseFloat($el.attr("max")) : null; } function getDecimalSeparator($el) { return $el.attr("decimal-separator") || ","; } function getDecimalSeparatorReplaced($el) { return getDecimalSeparator($el) === "," ? "." : ","; } function getPrefix($el) { return $el.attr("prefix") || ""; } function getSuffix($el) { return $el.attr("suffix") || ""; } // Controllo se il campo è disabilitato o in sola lettura function isDisabled($el) { return $el.prop("disabled") || $el.prop("readonly"); } function formatNumber($el, value, change = false) { if (!value && value !== 0) return buildFormattedValue($el, ""); const num = typeof value === "string" ? parseFloat(stripCurrency(value, $el).replace(",", ".")) : value; if (isNaN(num)) return buildFormattedValue($el, ""); // Applica limiti min e max const minVal = getMinVal($el); const maxVal = getMaxVal($el); if (minVal !== null && num < minVal) return formatNumber($el, minVal, change); if (maxVal !== null && num > maxVal) return formatNumber($el, maxVal, change); // Durante la digitazione, non completare i decimali if (!change) { const formattedNum = value.toString().replace(".", ","); return buildFormattedValue($el, formattedNum); } // Aggiungi decimali solo quando necessario (es. al blur) const fixedDecimals = getFixedDecimals($el); const formattedNum = num.toFixed(fixedDecimals).replace(".", ","); return buildFormattedValue($el, formattedNum); } function buildFormattedValue($el, value) { const prefix = getPrefix($el); const suffix = getSuffix($el); const currency = getCurrencySymbol($el); let formattedValue = ""; if (prefix) formattedValue += `${prefix} `; if (currency) formattedValue += `${currency} `; formattedValue += stripCurrency(value, $el); if (suffix) formattedValue += ` ${suffix}`; return formattedValue.trim(); } // Mi occupo di rimuovere il simbolo valuta dal valore function stripCurrency(value, $el) { if (!value) return ""; const currency = getCurrencySymbol($el); const prefix = getPrefix($el); const suffix = getSuffix($el); // Escapa prefissi e suffissi const escapedCurrency = currency.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const escapedPrefix = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const escapedSuffix = suffix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Costruisci il regex per rimuovere prefissi, suffissi e valuta const regexSuffix = new RegExp(`\\s*${escapedSuffix}$`); const regexPrefix = new RegExp(`^${escapedPrefix}\\s*`); const regexCurrency = new RegExp(`^${escapedCurrency}\\s*`); value = value.replace(regexPrefix, "").trim(); value = value.replace(regexCurrency, "").trim(); value = value.replace(regexSuffix, "").trim(); return value; } // Mi occupo di gestire l'incremento/decremento del valore function incrementValue(increment, $el) { if (isDisabled($el)) return; const cursorPos = $el.elements[0].selectionStart; let currentValue = parseFloat(stripCurrency($el.data("rawValue")?.toString().replace(",", ".") || "0", $el)) || 0; currentValue += parseFloat(increment); // Applico i vincoli di min/max const minVal = getMinVal($el); const maxVal = getMaxVal($el); if (minVal !== null && currentValue < minVal) currentValue = minVal; if (maxVal !== null && currentValue > maxVal) currentValue = maxVal; const rawValue = currentValue.toFixed(getFixedDecimals($el)); $el.data("rawValue", rawValue); $el.val(formatNumber($el, rawValue, true)); $el.trigger({ type: "change", internal: true, }); // Riposiziona il cursore tenendo conto di prefisso e suffisso let totalPrefixSuffixLength = 1; const prefixLength = getPrefix($el) ? getPrefix($el).length + 2 : 0; const currencyLength = getCurrencySymbol($el) ? getCurrencySymbol($el).length + 2 : 0; const suffixLength = getSuffix($el) ? getSuffix($el).length - 2 : 0; if (prefixLength > 0 && currencyLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = prefixLength + currencyLength - 1; } else if (prefixLength > 0 && currencyLength > 0) { totalPrefixSuffixLength = prefixLength + currencyLength; } else if (prefixLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = prefixLength; } else if (currencyLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = currencyLength; } else if (prefixLength > 0) { totalPrefixSuffixLength = prefixLength; } else if (currencyLength > 0) { totalPrefixSuffixLength = currencyLength; } const newPos = Math.max(cursorPos, totalPrefixSuffixLength); $el.elements[0].setSelectionRange(newPos, newPos); } $input.on("focus", function (e) { if (!isDisabled($CSD(e.target)) && !$arrows.is(":visible")) { var inputWidth = $CSD(e.target).outerWidth(); if (inputWidth < 100) return; // $arrows.toggle(); // var inputHeight = $CSD(e.target).outerHeight(); // var arrowsHeight = $arrows.outerHeight(); // var topPosition = 0; // var rightPosition = 16; // var $label = $CSD(e.target).closest(".csd-field").find("label"); // var labelHeight = 0; // var labelMargin = 0; // if ($label.elements.length > 0) { // labelMargin = parseFloat($label.css("margin-bottom")) || 0; // } // var paddingInput = // $CSD(e.target).css("padding-block").split(" ")[0].replace("px", "") * 2; // // Calcolo l'altezza dell'etichetta se è visibile e non inline // if ($label.is(":visible") && $label.closest(".csd-field-inline").elements > 0) { // labelHeight = $label.outerHeight(true); // topPosition = // (inputHeight - arrowsHeight) / 2 + // labelHeight - // paddingInput + // labelMargin + // "px"; // } else { // topPosition = paddingInput + labelMargin + "px"; // } // // Posiziono le frecce // $arrows.css({ // display: "inline-flex", // position: "absolute", // top: topPosition, // right: rightPosition + "px", // }); // Aggiungo padding a destra per evitare sovrapposizioni //$input.css("padding-right", rightPosition + $arrows.outerWidth() + "px"); } }); // Mi occupo di validare l'input mentre l'utente digita $input.on("input", function (e) { if (isDisabled($CSD(e.target))) return; let value = e.target.value; const cursorPos = this.selectionStart; const $el = $CSD(e.target); // Rimuovi prefissi, suffissi e valuta let cleanValue = stripCurrency(value, $el); cleanValue = cleanValue.replace(/[^\d,.-]/g, ""); // Controlla se i decimali sono abilitati const allowDecimals = getFixedDecimals($el) > 0; if (!allowDecimals) { cleanValue = cleanValue.replace(/[,\.]/g, ""); } else { const lastChar = value.slice(-1); const isComma = lastChar === ","; if (isComma && !cleanValue.includes(",")) { cleanValue += ","; } } // Controlla se ci sono separatori decimali multipli const separatorCount = (cleanValue.match(/[,\.]/g) || []).length; if (separatorCount > 1) { $el.val(buildFormattedValue($el, "")); $el.data("rawValue", ""); return; } // Costruisci il valore formattato const formattedValue = buildFormattedValue($el, cleanValue); $el.val(formattedValue); $el.data("rawValue", cleanValue.replace(",", ".")); // Riposiziona il cursore tenendo conto di prefisso e suffisso let totalPrefixSuffixLength = 0; const prefixLength = getPrefix($el) ? getPrefix($el).length + 2 : 0; const currencyLength = getCurrencySymbol($el) ? getCurrencySymbol($el).length + 2 : 0; const suffixLength = getSuffix($el) ? getSuffix($el).length - 2 : 0; if (prefixLength > 0 && currencyLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = prefixLength + currencyLength - 1; } else if (prefixLength > 0 && currencyLength > 0) { totalPrefixSuffixLength = prefixLength + currencyLength; } else if (prefixLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = prefixLength; } else if (currencyLength > 0 && suffixLength > 0) { totalPrefixSuffixLength = currencyLength; } else if (prefixLength > 0) { totalPrefixSuffixLength = prefixLength; } else if (currencyLength > 0) { totalPrefixSuffixLength = currencyLength; } const newPos = Math.max(cursorPos, totalPrefixSuffixLength); this.setSelectionRange(newPos, newPos); }); $input.on("blur", function (e) { if (isDisabled($CSD(e.target))) return; let value = stripCurrency($CSD(e.target).val(), $CSD(e.target)); if (!value) { $CSD(e.target).val(""); $CSD(e.target).data("rawValue", ""); //$arrows.hide(); $input.css("padding-right", ""); return; } // Completa i decimali se necessario const num = parseFloat(value.replace(",", ".")); if (!isNaN(num)) { const fixedDecimals = getFixedDecimals($CSD(e.target)); const rawValue = num.toFixed(fixedDecimals); const formattedValue = rawValue.replace(".", ","); $CSD(e.target).data("rawValue", rawValue); $CSD(e.target).val(buildFormattedValue($CSD(e.target), formattedValue)); } else { // In caso di valore non valido, resetta il campo $CSD(e.target).val(""); $CSD(e.target).data("rawValue", ""); } //$arrows.hide(); $input.css("padding-right", ""); }); // Mi occupo di gestire gli eventi di cambio valore $input.on("change", function (e) { if (isDisabled($CSD(e.target))) return; let value = stripCurrency($CSD(e.target).val(), $CSD(e.target)); if (!value) { $CSD(e.target).val(""); $CSD(e.target).data("rawValue", ""); return; } // Completa i decimali se necessario const num = parseFloat(value.replace(",", ".")); if (!isNaN(num)) { const fixedDecimals = getFixedDecimals($CSD(e.target)); const rawValue = num.toFixed(fixedDecimals); const formattedValue = rawValue.replace(".", ","); $CSD(e.target).data("rawValue", rawValue); $CSD(e.target).val(buildFormattedValue($CSD(e.target), formattedValue)); } }); // Mi occupo di gestire le frecce da tastiera $input.on("keydown", function (event) { if (isDisabled($CSD(event.target))) return; if (event.key === "ArrowUp" || event.key === "ArrowDown") { event.preventDefault(); const increment = event.key === "ArrowUp" ? getStep($CSD(event.target)) : -getStep($CSD(event.target)); incrementValue(increment, $CSD(event.target)); } else if (event.key === "ArrowLeft" || event.key === "ArrowRight") { const cursorPos = this.selectionStart; const value = $CSD(this).val(); const prefix = getPrefix($CSD(this)); const suffix = getSuffix($CSD(this)); const currency = getCurrencySymbol($CSD(this)); const prefixLength = prefix ? prefix.length + 1 : 0; const currencyLength = currency ? currency.length + 2 : 0; const suffixLength = suffix ? suffix.length + 1 : 0; const startPos = prefixLength + currencyLength; const endPos = value.length - suffixLength; let newPos = cursorPos; if (event.key === "ArrowLeft" && cursorPos <= startPos) { newPos = startPos; } else if (event.key === "ArrowRight" && cursorPos >= endPos) { newPos = endPos; } if (cursorPos < startPos || cursorPos > endPos) { newPos = event.key === "ArrowLeft" ? startPos : endPos; } if (newPos !== cursorPos) { event.preventDefault(); this.setSelectionRange(newPos, newPos); } } }); // Inizializzo il valore iniziale del campo const initialValue = $input.val(); if (initialValue) { const currencySymbol = getCurrencySymbol($input); const decimalSeparator = getDecimalSeparator($input); let numValue = stripCurrency(initialValue, $input); // Converte e formatta il valore iniziale numValue = parseFloat(numValue.replace(decimalSeparator, ".")).toFixed( getFixedDecimals($input) ); $input.data("rawValue", numValue); $input.val(formatNumber($input, numValue, true)); } $arrows.find(".csd-arrow-btn").on("click", function (event) { $CSD(event.target).closest(".csd-input-group").find(".csd-number").focus(); // Mantengo il focus sull'input if (isDisabled($CSD(event.target))) return; const increment = $CSD(this).hasClass("up") ? getStep($CSD(event.target).closest(".csd-input-group").find(".csd-number")) : -getStep( $CSD(event.target).closest(".csd-input-group").find(".csd-number") ); incrementValue( increment, $CSD(event.target).closest(".csd-input-group").find(".csd-number") ); }); } export { initializeNumber };