UNPKG

live-number-format

Version:

A tiny Javascript library that gives live as-you-type formatting to numbers & currencies, ~1600 bytes minified + gzipped.

1 lines 5.39 kB
export default class LiveNumberFormat{constructor(e,t={}){this.el=e,this.undoStack=[],this.redoStack=[],this.debounceTimer=null,this.debounceTime=t.debounceTime||300,this.allowNegative=void 0===t.allowNegative||t.allowNegative,this.formatStyle=void 0!==t.formatStyle?t.formatStyle:"thousand",this.decimalMark=".",this.delimiter=",",this.decimalScale=void 0!==t.decimalScale?t.decimalScale:1/0,this.integerScale=void 0!==t.integerScale?t.integerScale:1/0,this.stripLeadingZeroes=void 0!==t.stripLeadingZeroes&&t.stripLeadingZeroes,this.allowDecimalReplacement=void 0!==t.allowDecimalReplacement&&t.allowDecimalReplacement,this.maxUndoStackSize=t.maxUndoStackSize||500,this.handleInput=this.handleInput.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.backspacePressed=!1,this.isChangeFromUndoRedo=!1,this.init(),this.el.value&&(this.handleInput(),this.setCursorPosition(this.el.value.length))}init(){this.el.addEventListener("input",this.handleInput),this.el.addEventListener("keydown",this.handleKeydown)}format(e){let t,i,s,a="";switch(e=e.replace(/[A-Za-z]/g,"").replace(this.decimalMark,"D").replace(/[^\dD-]/g,"").replace(/^\-/,"M").replace(/\-/g,"").replace("M",this.allowNegative?"-":"").replace("D",this.decimalMark),i="-"===(e=this.stripLeadingZeroes?e.replace(/^(-)?0+(?=\d)/,"$1"):e).slice(0,1)?"-":"",t=this.getParts(e,!0,!0),s=t.partInteger,"-"==i&&(s=t.partInteger.slice(1)),e.includes(this.decimalMark)&&(a=this.decimalMark+t.partDecimal),this.formatStyle){case"thousandLakhCrore":s=s.replace(/(\d)(?=(\d\d)+\d$)/g,"$1"+this.delimiter);break;case"thousand":s=s.replace(/(\d)(?=(\d{3})+$)/g,"$1"+this.delimiter);break;case"tenThousand":s=s.replace(/(\d)(?=(\d{4})+$)/g,"$1"+this.delimiter)}return i+s.toString()+(0<this.decimalScale?a.toString():"")}handleInput(e){clearTimeout(this.debounceTimer);let t=this.el.value,i=this.el.selectionEnd,s;if(this.stripLeadingZeroes||!t.match(new RegExp(`^[${this.delimiter}0]*$`))){s=this.format(this.el.value);const a=this.getNextCursorPosition(i,t,s);this.el.value=s,this.setCursorPosition(a),this.isChangeFromUndoRedo||(this.debounceTimer=setTimeout(()=>{this.pushToUndoStack({val:s,cpos:a})},this.debounceTime))}this.isChangeFromUndoRedo=!1}setCursorPosition(e){this.el.setSelectionRange(e=e<0?0:e,e)}getNextCursorPosition(e,t,i){return t.length===e?i.length:e+this.getPositionOffset(e,t,i)}getDelimiterRegex(){return new RegExp(this.delimiter,"g")}getParts(e,t=!1,i=!1){e=e.split(this.decimalMark);let s=e[0],a="";return 1<e.length&&(a=e[1]),t&&(s=s.replace(this.getDelimiterRegex(),""),a=a.replace(this.getDelimiterRegex(),"")),i&&(s=s.slice(0,this.integerScale),a=a.slice(0,this.decimalScale)),{partInteger:s,partDecimal:a}}getPositionOffset(e,t,i){if(t.startsWith("-"+this.delimiter)&&i.startsWith("-"))return 0;let s,a,l,r;return r=t.slice(e),l=i.slice(e),s=t.slice(0,e).replace(this.getDelimiterRegex(),""),a=i.slice(0,e).replace(this.getDelimiterRegex(),""),s=s.replace("-",""),a=a.replace("-",""),s.includes("-")||s.match(/[^0-9\.-]/)||this.stripLeadingZeroes&&"0"===s||r!=l&&this.backspacePressed&&r.startsWith(this.delimiter)?-1:Math.sign(s.length-a.length)}handleKeydown(e){if(this.backspacePressed=!1,"Backspace"===e.key)this.backspacePressed=!0;else{if("ArrowLeft"===e.key&&!e.shiftKey)return void this.handleLeftArrow(e);if("ArrowRight"===e.key&&!e.shiftKey)return void this.handleRightArrow(e);if(e.ctrlKey&&("z"===e.key||"Z"===e.key))return void this.performUndo(e);if(e.ctrlKey&&("y"===e.key||"Y"===e.key))return void this.performRedo(e);if("Delete"===e.key)return void(this.el.value[this.el.selectionStart]===this.delimiter&&0!=this.el.selectionStart&&(e.preventDefault(),this.setCursorPosition(this.el.selectionStart+1)))}var t,i;e.key===this.decimalMark&&(!1===this.allowDecimalReplacement&&this.el.value.includes(this.decimalMark)||0===this.decimalScale)&&e.preventDefault(),this.el.selectionStart===this.el.selectionEnd&&["0","1","2","3","4","5","6","7","8","9"].includes(e.key)&&(t=this.getParts(this.el.value,!0),i=this.el.value.split(this.delimiter).length-1,(i=this.el.selectionStart-i)<=t.partInteger.length&&t.partInteger.length>=this.integerScale&&e.preventDefault(),i>t.partInteger.length)&&t.partDecimal.length>=this.decimalScale&&e.preventDefault()}handleLeftArrow(e){var t=this.el.selectionStart;t-2<0||this.el.value[t-2]===this.delimiter&&(e.preventDefault(),this.setCursorPosition(t-2))}handleRightArrow(e){var t=this.el.selectionStart;this.el.value[t]===this.delimiter&&(e.preventDefault(),this.setCursorPosition(t+2))}pushToUndoStack(e){this.undoStack.length<=this.maxUndoStackSize&&(this.undoStack.push(e),this.redoStack=[])}performUndo(){var e;this.isChangeFromUndoRedo=!0,1<this.undoStack.length?(e=this.undoStack.pop(),this.redoStack.push(e),e=this.undoStack[this.undoStack.length-1],this.el.value=e.val,this.setCursorPosition(e.cpos)):1===this.undoStack.length&&(this.redoStack.push(this.undoStack.pop()),this.el.value="")}performRedo(){var e;this.isChangeFromUndoRedo=!0,0<this.redoStack.length&&(e=this.redoStack.pop(),this.undoStack.push(e),this.el.value=e.val,this.setCursorPosition(e.cpos))}destroy(){this.el.removeEventListener("input",this.handleInput),this.el.removeEventListener("keydown",this.handleKeydown)}getRawValue(){return this.el.value}getFloatValue(){let e=this.getRawValue();return e=e&&e.match(/[0-9.-]+/g).join(""),!0===isNaN(parseFloat(e))?0:parseFloat(e)}}