UNPKG

@fto-consult/common

Version:

Un ensemble de bibliothèques et d'utilistaires communs pour le développement d'applications javascript

440 lines (406 loc) 14.3 kB
// Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. import defaultStr from "$cutils/defaultStr"; import fNumber from "./formatNumber"; import Currency from "$ccurrency"; import isNonNullString from "./isNonNullString"; // Got this from MDN: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString#Example:_Checking_for_support_for_locales_and_options_arguments function toLocaleStringSupportsLocales() { var number = 0; try { number.toLocaleString("i"); } catch (e) { return e.name === "RangeError"; } return false; } if (!toLocaleStringSupportsLocales()) { var replaceSeparators = function(sNum, separators) { var sNumParts = sNum.split('.'); if (separators && separators.thousands) { sNumParts[0] = sNumParts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + separators.thousands); } sNum = sNumParts.join(separators.decimal); return sNum; }; var renderFormat = function(template, props) { for (var prop in props) { if (props[prop].indexOf('-') !== -1) { props[prop] = props[prop].replace('-', ''); template = '-' + template; } template = template.replace("{{" + prop + "}}", props[prop]); } return template; }; var mapMatch = function(map, locale) { var match = locale; var language = locale && locale.toLowerCase().match(/^\w+/); if (!map.hasOwnProperty(locale)) { if (map.hasOwnProperty(language)) { match = language; } else { match = "en"; } } return map[match]; }; var dotThousCommaDec = function(sNum) { var separators = { decimal: ',', thousands: '.' }; return replaceSeparators(sNum, separators); }; var commaThousDotDec = function(sNum) { var separators = { decimal: '.', thousands: ',' }; return replaceSeparators(sNum, separators); }; var spaceThousCommaDec = function(sNum) { var seperators = { decimal: ',', thousands: '\u00A0' }; return replaceSeparators(sNum, seperators); }; var apostrophThousDotDec = function(sNum) { var seperators = { decimal: '.', thousands: '\u0027' }; return replaceSeparators(sNum, seperators); }; var transformForLocale = { en: commaThousDotDec, 'en-GB': commaThousDotDec, 'en-US': commaThousDotDec, it: dotThousCommaDec, fr: spaceThousCommaDec, de: dotThousCommaDec, "de-DE": dotThousCommaDec, "de-AT": dotThousCommaDec, "de-CH": apostrophThousDotDec, "de-LI": apostrophThousDotDec, "de-BE": dotThousCommaDec, "nl": dotThousCommaDec, "nl-BE": dotThousCommaDec, "nl-NL": dotThousCommaDec, ro: dotThousCommaDec, "ro-RO": dotThousCommaDec, ru: spaceThousCommaDec, "ru-RU": spaceThousCommaDec, hu: spaceThousCommaDec, "hu-HU": spaceThousCommaDec, "da-DK": dotThousCommaDec, "nb-NO": spaceThousCommaDec }; var currencyFormatMap = { en: "pre", 'en-GB': "pre", 'en-US': "pre", it: "post", fr: "post", de: "post", "de-DE": "post", "de-AT": "prespace", "de-CH": "prespace", "de-LI": "post", "de-BE": "post", "nl": "post", "nl-BE": "post", "nl-NL": "post", ro: "post", "ro-RO": "post", ru: "post", "ru-RU": "post", hu: "post", "hu-HU": "post", "da-DK": "post", "nb-NO": "post" }; const currencySymbols = { "afn": "؋", "ars": "$", "awg": "ƒ", "aud": "$", "azn": "₼", "bsd": "$", "bbd": "$", "byr": "p.", "bzd": "BZ$", "bmd": "$", "bob": "Bs.", "bam": "KM", "bwp": "P", "bgn": "лв", "brl": "R$", "bnd": "$", "khr": "៛", "cad": "$", "kyd": "$", "clp": "$", "cny": "¥", "cop": "$", "crc": "₡", "hrk": "kn", "cup": "₱", "czk": "Kč", "dkk": "kr", "dop": "RD$", "xcd": "$", "egp": "£", "svc": "$", "eek": "kr", "eur": "€", "fkp": "£", "fjd": "$", "ghc": "¢", "gip": "£", "gtq": "Q", "ggp": "£", "gyd": "$", "hnl": "L", "hkd": "$", "huf": "Ft", "isk": "kr", "inr": "₹", "idr": "Rp", "irr": "﷼", "imp": "£", "ils": "₪", "jmd": "J$", "jpy": "¥", "jep": "£", "kes": "KSh", "kzt": "лв", "kpw": "₩", "krw": "₩", "kgs": "лв", "lak": "₭", "lvl": "Ls", "lbp": "£", "lrd": "$", "ltl": "Lt", "mkd": "ден", "myr": "RM", "mur": "₨", "mxn": "$", "mnt": "₮", "mzn": "MT", "nad": "$", "npr": "₨", "ang": "ƒ", "nzd": "$", "nio": "C$", "ngn": "₦", "nok": "kr", "omr": "﷼", "pkr": "₨", "pab": "B/.", "pyg": "Gs", "pen": "S/.", "php": "₱", "pln": "zł", "qar": "﷼", "ron": "lei", "rub": "₽", "shp": "£", "sar": "﷼", "rsd": "Дин.", "scr": "₨", "sgd": "$", "sbd": "$", "sos": "S", "zar": "R", "lkr": "₨", "sek": "kr", "chf": "CHF", "srd": "$", "syp": "£", "tzs": "TSh", "twd": "NT$", "thb": "฿", "ttd": "TT$", "try": "", "trl": "₤", "tvd": "$", "ugx": "USh", "uah": "₴", "gbp": "£", "usd": "$", "uyu": "$U", "uzs": "лв", "vef": "Bs", "vnd": "₫", "yer": "﷼", "zwd": "Z$" }; const currencyFormats = { pre: "{{code}}{{num}}", post: "{{num}} {{code}}", prespace: "{{code}} {{num}}" }; Number.prototype.toLocaleString = function(locale, options) { if (locale && locale.length < 2) throw new RangeError("Invalid language tag: " + locale); var sNum; if (options && (options.minimumFractionDigits || options.minimumFractionDigits === 0)) { sNum = this.toFixed(options.minimumFractionDigits); } else { sNum = this.toString(); } sNum = mapMatch(transformForLocale, locale)(sNum, options); if(options && options.currency && options.style === "currency") { var format = currencyFormats[mapMatch(currencyFormatMap, locale)]; var symbol = currencySymbols[options.currency.toLowerCase()]; if(options.currencyDisplay === "code" || !symbol) { sNum = renderFormat(format, { num: sNum, code: options.currency.toUpperCase() }); } else { sNum = renderFormat(format, { num: sNum, code: symbol }); } } return sNum; }; } /*** compte le nombre de décimales sur le nombre passé en paramètre */ Number.prototype.countDecimals = function () { if(Math.floor(this.valueOf()) === this.valueOf()) return 0; let str = this.toString().split(".")[1]; return str ? str.length : 0; } Number.prototype.formatNumber = function(locale,options){ let val = this.valueOf(); let decimals = val.countDecimals(); if(!isNonNullString(locale)){ locale = decimals == 0 ? '# ###' : decimals == 1 ? '# ###.#' : decimals == 2 ? '# ###.##' : '# ###.###'; } if(locale.contains("###")){ return fNumber.formatNumber(val,locale); } return Number.prototype.toLocaleString.call(this,locale,defaultObj(options)) } String.prototype.formatNumber = function(locale,options){ locale = defaultStr(locale,'fr'); let str = defaultStr(this.toString(),"0") let number = str.parseNumber(locale); return number.formatNumber(locale,options); } /***** parse une chaine de caractère en un nombre */ String.prototype.parseNumber = function(format){ format = defaultStr(format,'# ###.##'); let str = defaultStr(this.toString(),"0") if(format.contains("###")){ return fNumber.parseNumber(str,format); } else { return parseDecimal(str.replaceAll(" ","")) } } String.prototype.parseToDecimal = function(){ let v = this.toString() || ''; let _v = v.replaceAll(("0").formatMoney().replaceAll("0","")," ").trim().replaceAll(" ",""); let regex = /[+-]?\d+(?:\.\d+)?/g; let matches = _v.match(regex); if(matches && _v == matches[0]){ return parseDecimal(_v); } return v; } /*** * formate un nombre en devise : symbol, decimal_digits, thousand, decimal, format @param {String} symbol, le symbole de la devise @param {number} decimal_digits, le nombre de décimales @param {string} thousand, le séparateur de milliers @param {string} decimal, le séparateur de décimales @param {string} format, le format d'affichage de la dévise par exemple : %s %v .## @param {boolean} returnObject, si true alors un objet sera retourné @return {string}, le nombre formatté au format money */ Number.prototype.formatMoney = function(symbol, decimal_digits, thousand, decimal, format,returnObject){ return Currency.formatMoney(this.valueOf(),symbol, decimal_digits, thousand, decimal, format,returnObject); } /*** * formate un nombre en devise : symbol, decimal_digits, thousand, decimal, format @param {String} symbol, le symbole de la devise @param {number} decimal_digits, le nombre de décimales @param {string} thousand, le séparateur de milliers @param {string} decimal, le séparateur de décimales @param {string} format, le format d'affichage de la dévise par exemple : %s %v .## @return {string}, le nombre formatté au format money @param {boolean} returnObject, si true alors un objet sera retourné */ String.prototype.formatMoney = function(symbol, decimal_digits, thousand, decimal, format,returnObject){ return Currency.formatMoney((this.toString().replaceAll(" ",'')),symbol, decimal_digits, thousand, decimal, format,returnObject); } /**** @see : https://stackoverflow.com/questions/10599933/convert-long-number-into-abbreviated-string-in-javascript-with-a-special-shortn */ const _abreviateNumber = (num, returnObject) =>{ if (num === null || typeof num !=='number') { returnObject === true ? {} : null} // terminate early const decimals = num.countDecimals(); let fixed = Math.min(decimals,5); fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show if (num == 0) { num = num != 0 ? parseFloat(num.toFixed(0 + fixed)) || 0 : 0; const nString = num.toString(); return returnObject === true ? { formattedResult :nString, value : num, format : '', suffix : '', formattedValue : nString, } : nString; } // terminate early var b = (num).toPrecision(2).split("e"), // get power k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power d = c < 0 ? c : Math.abs(c), // enforce -0 is 0 e = d; // append power const suffix = ['', 'K', 'M', 'B', 'T'][k]; const value = parseFloat(e) ||0; if(returnObject ===true){ return { formattedValue : e, value, suffix, format : suffix, formattedResult : e+suffix, } } return (value).formatNumber()+suffix; }; export const abreviateNumber = (num)=>{ return _abreviateNumber(num,false); } /*** permet d'abréger un nombre en kilo, ainsi de suite */ Number.prototype.abreviate = function(){ return abreviateNumber(this.valueOf()); } /****abbrège un nombre et le formate en devise * @param {number} number le nombre a formatter et abréger @param {String} symbol, le symbole de la devise @param {number} decimal_digits, le nombre de décimales @param {string} thousand, le séparateur de milliers @param {string} decimal, le séparateur de décimales @param {string} format, le format d'affichage de la dévise par exemple : %s %v .## @return {string}, le nombre formatté au format money @param {boolean} returnObject, si true alors un objet sera retourné */ export const abreviate2FormatMoney = (number,symbol, decimal_digits, thousand, decimal, format)=>{ const {value,format:fStr,formattedValue} = _abreviateNumber(number,true); if(typeof value !='number') return formattedValue; const {formattedValue:fVal} = Currency.formatMoney(value,symbol, decimal_digits, thousand, decimal, format,true); return fVal.replace('%v',Math.abs(value).formatNumber()+fStr); } Number.prototype.abreviate2FormatMoney = Number.prototype.abreviate2formatMoney = function(){ return abreviate2FormatMoney(this.valueOf()); }