1(function (window, document, $, tcg) { 2 function resolveAllowDecimal(cfg) { 3 if (cfg.allowDecimal === undefined || cfg.allowDecimal === null) { 4 return cfg.decimal !== false; 5 } 6 return cfg.allowDecimal === "Y"; 7 } 8 9 tcg.mc.easyNumberSeparator = (config) => { 10 // Currency Separator 11 const allowDecimal = resolveAllowDecimal(config); 12 const obj = { 13 selector: config.selector || ".number-separator", 14 separator: config.separator || ",", 15 decimalSeparator: config.decimalSeparator || ".", 16 resultInput: config.resultInput, 17 allowDecimal, 18 decimal: allowDecimal, 19 forceDecimal: tcg.mc.currency === "IDRK" || config.forceDecimal || false, 20 maxIntegerDigits: tcg.mc.currency === "IDRK" ? 15 : null, // éå¶æ´æ¸ä½æ¸ 21 listenPointer: config.listenPointer ?? true, 22 }; 23 if (!obj.allowDecimal) { 24 obj.forceDecimal = false; 25 } 26 function clampCaretToInteger(input, dotChar) { 27 const v = input.value || ""; 28 const dot = v.indexOf(dotChar); 29 if (dot === -1) return; 30 const start = input.selectionStart ?? 0; 31 const end = input.selectionEnd ?? 0; 32 if (start > dot || end > dot) input.setSelectionRange(dot, dot); 33 } 34 35 function listenSelectionClamp() { 36 const sel = obj.selector; 37 38 $(document) 39 .off("focusin.decimalClamp focusout.decimalClamp", sel) 40 .on("focusin.decimalClamp", sel, function () { 41 const el = this; 42 const handler = function () { 43 if (!obj.forceDecimal) return; 44 if (document.activeElement !== el) return; 45 clampCaretToInteger(el, tcg.mc.getDecimalSeparator()); 46 }; 47 $(el).data("decimalClampHandler", handler); 48 document.addEventListener("selectionchange", handler, { passive: true }); 49 }) 50 .on("focusout.decimalClamp", sel, function () { 51 const el = this; 52 const handler = $(el).data("decimalClampHandler"); 53 if (handler) { 54 document.removeEventListener("selectionchange", handler); 55 $(el).removeData("decimalClampHandler"); 56 } 57 }); 58 } 59 60 function listenKeydownHard() { 61 $(obj.selector) 62 .off("keydown.decimalClamp") 63 .on("keydown.decimalClamp", function (e) { 64 if (!obj.forceDecimal) return; 65 66 const el = this; 67 const val = el.value || ""; 68 const dotChar = tcg.mc.getDecimalSeparator(); 69 const dot = val.indexOf(dotChar); 70 if (dot === -1) return; 71 72 const s = el.selectionStart ?? 0; 73 const epos = el.selectionEnd ?? 0; 74 const crosses = s < dot && epos > dot; 75 const atOrAfterDot = s >= dot || crosses; 76 77 const isDigit = (e.key >= "0" && e.key <= "9") || (e.code && /Numpad[0-9]/.test(e.code)); 78 const isDotKey = e.key === "." || e.key === ","; 79 80 if (isDigit || isDotKey) { 81 const atAfterDotStrict = s > dot || crosses; 82 if (atAfterDotStrict) { 83 e.preventDefault(); 84 el.setSelectionRange(dot, dot); 85 return; 86 } 87 } 88 89 if (e.key === "ArrowRight" || e.key === "End") { 90 if (atOrAfterDot) { 91 e.preventDefault(); 92 el.setSelectionRange(dot, dot); 93 } 94 } 95 }); 96 } 97 98 function listenKeydown() { 99 $(obj.selector) 100 .off("keydown.numberSeparator") 101 .on("keydown.numberSeparator", function (e) { 102 if (!obj.forceDecimal) return; 103 const dotChar = tcg.mc.getDecimalSeparator(); 104 const val = this.value; 105 const dotPos = val.indexOf(dotChar); 106 const intPart = dotPos === -1 ? val : val.slice(0, dotPos); 107 const intDigits = intPart.replace(/\D/g, "").length; 108 const maxInt = obj.maxIntegerDigits; 109 110 if (/^\d$/.test(e.key)) { 111 if (dotPos === -1 || this.selectionStart <= dotPos) { 112 if (maxInt && intDigits >= maxInt) { 113 e.preventDefault(); 114 return; 115 } 116 } 117 } 118 if (dotPos === -1) return; 119 const selectionStart = this.selectionStart; 120 const selectionEnd = this.selectionEnd; 121 if (e.key === "ArrowRight" || e.key === "End") { 122 if (selectionStart > dotPos || (selectionStart < dotPos && selectionEnd > dotPos)) { 123 e.preventDefault(); 124 this.setSelectionRange(dotPos, dotPos); 125 } 126 } 127 }); 128 } 129 130 function listenPointer() { 131 $(obj.selector) 132 .off("mouseup.numberSeparator click.numberSeparator select.numberSeparator touchend.numberSeparator") 133 .on( 134 "mouseup.numberSeparator click.numberSeparator select.numberSeparator touchend.numberSeparator", 135 function () { 136 if (!obj.forceDecimal) return; 137 const el = this; 138 const dotChar = tcg.mc.getDecimalSeparator(); 139 setTimeout(function () { 140 clampCaretToInteger(el, dotChar); 141 }, 0); 142 } 143 ); 144 } 145 146 function numberSeparator(val, maxLength) { 147 if (tcg.mc.currency === "IDRK") { 148 obj.decimal = 3; 149 obj.forceDecimal = true; 150 } 151 if (!val) { 152 return ""; 153 } 154 let num = val; 155 const el = $(obj.selector).get(0); 156 const dot = tcg.mc.getDecimalSeparator(); 157 const caret = el ? el.selectionStart : null; 158 const dotIndex = val.indexOf(dot); 159 const editingFraction = dotIndex !== -1 && caret !== null && caret > dotIndex; 160 161 const endWithDecimal = num && num.endsWith(dot); 162 const parseNum = tcg.mc.parseFormatNumber(num); 163 const currentFracLen = dotIndex !== -1 ? (val.split(dot)[1] || "").length : 0; 164 const decimalLength = obj.forceDecimal && !editingFraction ? 3 : Math.min(3, currentFracLen); 165 166 if (String(parseNum).length > maxLength) { 167 const truncated = String(parseNum).slice(0, maxLength); 168 return tcg.mc.currencyFormat(truncated, decimalLength); 169 } 170 171 const decimal = obj.decimal ? decimalLength : 0; 172 const value = tcg.mc.currencyFormat(parseNum, decimal); 173 const regex = /^([^,]*,){2}[^,]*$/; 174 const singleComma = !regex.test(val); 175 if (endWithDecimal && tcg.mc.currency === "IDRK") return value; 176 num = val === "-" ? null : value + (endWithDecimal && singleComma ? dot : ""); 177 178 if (tcg.mc.currency === "IDRK" && obj.forceDecimal && num && !editingFraction) { 179 setTimeout(function () { 180 const inputValue = $(obj.selector).val(); 181 const dotChar = tcg.mc.getDecimalSeparator(); 182 const dotIndexs = inputValue.indexOf(dotChar); 183 let focusPos; 184 if (dotIndexs !== -1) { 185 focusPos = dotIndexs; 186 } else { 187 const commas = (inputValue.match(/,/g) || []).length; 188 const intLen = String(parseNum).split(".")[0].length; 189 focusPos = intLen + commas; 190 } 191 $(obj.selector).focus().get(0).setSelectionRange(focusPos, focusPos); 192 }, 0); 193 } 194 195 return num; 196 } 197 function listenKeydownIntegerOnly() { 198 $(obj.selector) 199 .off("keydown.integerOnly")
200 .on("keydown.integerOnly", function (e) { 201 if (obj.allowDecimal) return; 202 const dotChar = tcg.mc.getDecimalSeparator(); 203 if (e.key === dotChar || e.code === "NumpadDecimal") { 204 e.preventDefault(); 205 } 206 }); 207 } 208 209 function numberSeparatorNormal(val) { 210 if (!val) { 211 return ""; 212 } 213 let num = val; 214 const dot = tcg.mc.getDecimalSeparator(); 215 const endWithDecimal = obj.allowDecimal && num && num.endsWith(dot); 216 let parseNum = tcg.mc.parseFormatNumber(num); 217 if (!obj.allowDecimal && Number.isFinite(parseNum)) { 218 parseNum = Math.trunc(parseNum); 219 } 220 const decimalLength = obj.decimal ? Math.min(2, `${num}`.split(dot)[1]?.length || 0) : 0; 221 const decimal = obj.decimal ? decimalLength : 0; 222 const value = tcg.mc.currencyFormat(parseNum, decimal); 223 const regex = /^([^,]*,){2}[^,]*$/; 224 const singleComma = !regex.test(val); 225 num = val === "-" ? null : value + (endWithDecimal && singleComma ? dot : ""); 226 227 return num; 228 } 229 230 function listenFields() { 231 $(obj.selector) 232 .off("input.numberSeparator") 233 .on("input.numberSeparator", function (e) { 234 const max = $(e.target).data("maxLength"); 235 this.value = obj.listenPointer ? numberSeparator(this.value, max) : numberSeparatorNormal(this.value); 236 const parsedNum = tcg.mc.parseFormatNumber(this.value); 237 const attrStr = typeof parsedNum === "number" && Number.isFinite(parsedNum) ? String(parsedNum) : ""; 238 this.setAttribute("formatamount", attrStr); 239 }); 240 } 241 242 listenFields(); 243 if (obj.listenPointer) { 244 listenKeydown(); 245 listenPointer(); 246 listenKeydownHard(); 247 listenSelectionClamp(); 248 } else if (!obj.allowDecimal) { 249 listenKeydownIntegerOnly(); 250 } 251 }; 252})(window, document, jQuery, window.tcg || {});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.