@ngodings/ngx-rupiah
Version:
Angular directive mask for currency Rupiah/IDR support for NgModule or Reactive forms, pipe for currency Rupiah/IDR & pipe for terbilang in Rupiah/IDR
1 lines • 65.4 kB
Source Map (JSON)
{"version":3,"file":"ngodings-ngx-rupiah.mjs","sources":["../../../packages/ngx-rupiah/src/lib/rupiah-mask.config.ts","../../../packages/ngx-rupiah/src/lib/input.manager.ts","../../../packages/ngx-rupiah/src/lib/input.service.ts","../../../packages/ngx-rupiah/src/lib/input.handler.ts","../../../packages/ngx-rupiah/src/lib/rupiah-mask.directive.ts","../../../packages/ngx-rupiah/src/lib/rupiah.service.ts","../../../packages/ngx-rupiah/src/lib/terbilang.pipe.ts","../../../packages/ngx-rupiah/src/lib/rupiah.pipe.ts","../../../packages/ngx-rupiah/src/lib/rupiah-mask.module.ts","../../../packages/ngx-rupiah/src/public-api.ts","../../../packages/ngx-rupiah/src/ngodings-ngx-rupiah.ts"],"sourcesContent":["import { InjectionToken } from \"@angular/core\";\n\nexport interface RupiahMaskConfig {\n align: string;\n allowNegative: boolean;\n allowZero: boolean;\n decimal: string;\n precision: number;\n prefix: string;\n suffix: string;\n thousands: string;\n nullable: boolean;\n min?: number;\n max?: number;\n inputMode?: RupiahMaskInputMode;\n}\n\nexport enum RupiahMaskInputMode {\n FINANCIAL,\n NATURAL,\n}\n\nexport let RUPIAH_MASK_CONFIG = new InjectionToken<RupiahMaskConfig>(\"currency.mask.config\");","export class InputManager {\n\n private _storedRawValue: string | undefined;\n\n constructor(private htmlInputElement: any) {\n }\n\n setCursorAt(position: number): void {\n if (this.htmlInputElement.setSelectionRange) {\n this.htmlInputElement.focus();\n this.htmlInputElement.setSelectionRange(position, position);\n } else if (this.htmlInputElement.createTextRange) {\n let textRange = this.htmlInputElement.createTextRange();\n textRange.collapse(true);\n textRange.moveEnd(\"character\", position);\n textRange.moveStart(\"character\", position);\n textRange.select();\n }\n }\n\n updateValueAndCursor(newRawValue: string, oldLength: number, selectionStart: number): void {\n this.rawValue = newRawValue;\n let newLength = newRawValue.length;\n selectionStart = selectionStart - (oldLength - newLength);\n this.setCursorAt(selectionStart);\n }\n\n get canInputMoreNumbers(): boolean {\n let onlyNumbers = this.rawValue.replace(/[^0-9\\u0660-\\u0669\\u06F0-\\u06F9]/g, \"\");\n let haventReachedMaxLength = !(onlyNumbers.length >= this.htmlInputElement.maxLength && this.htmlInputElement.maxLength >= 0);\n let selectionStart = this.inputSelection.selectionStart;\n let selectionEnd = this.inputSelection.selectionEnd;\n let haveNumberSelected = !!(selectionStart != selectionEnd &&\n this.htmlInputElement.value.substring(selectionStart, selectionEnd).match(/[^0-9\\u0660-\\u0669\\u06F0-\\u06F9]/));\n let startWithZero = (this.htmlInputElement.value.substring(0, 1) == \"0\");\n return haventReachedMaxLength || haveNumberSelected || startWithZero;\n }\n\n get inputSelection(): any {\n let selectionStart = 0;\n let selectionEnd = 0;\n\n if (typeof this.htmlInputElement.selectionStart == \"number\" && typeof this.htmlInputElement.selectionEnd == \"number\") {\n selectionStart = this.htmlInputElement.selectionStart;\n selectionEnd = this.htmlInputElement.selectionEnd;\n } else {\n let range = (<any>document).selection.createRange();\n\n if (range && range.parentElement() == this.htmlInputElement) {\n let lenght = this.htmlInputElement.value.length;\n let normalizedValue = this.htmlInputElement.value.replace(/\\r\\n/g, \"\\n\");\n let startRange = this.htmlInputElement.createTextRange();\n startRange.moveToBookmark(range.getBookmark());\n let endRange = this.htmlInputElement.createTextRange();\n endRange.collapse(false);\n\n if (startRange.compareEndPoints(\"StartToEnd\", endRange) > -1) {\n selectionStart = selectionEnd = lenght;\n } else {\n selectionStart = -startRange.moveStart(\"character\", -lenght);\n selectionStart += normalizedValue.slice(0, selectionStart).split(\"\\n\").length - 1;\n\n if (startRange.compareEndPoints(\"EndToEnd\", endRange) > -1) {\n selectionEnd = lenght;\n } else {\n selectionEnd = -startRange.moveEnd(\"character\", -lenght);\n selectionEnd += normalizedValue.slice(0, selectionEnd).split(\"\\n\").length - 1;\n }\n }\n }\n }\n\n return {\n selectionStart: selectionStart,\n selectionEnd: selectionEnd\n };\n }\n\n get rawValue(): string {\n return this.htmlInputElement && this.htmlInputElement.value;\n }\n\n set rawValue(value: string) {\n this._storedRawValue = value;\n\n if (this.htmlInputElement) {\n this.htmlInputElement.value = value;\n }\n }\n\n get storedRawValue(): string {\n return this._storedRawValue || '';\n }\n}","import { InputManager } from \"./input.manager\";\nimport { RupiahMaskConfig, RupiahMaskInputMode } from \"./rupiah-mask.config\";\n\nexport class InputService {\n private SINGLE_DIGIT_REGEX: RegExp = new RegExp(/^[0-9\\u0660-\\u0669\\u06F0-\\u06F9]$/);\n private ONLY_NUMBERS_REGEX: RegExp = new RegExp(/[^0-9\\u0660-\\u0669\\u06F0-\\u06F9]/g);\n\n PER_AR_NUMBER: Map<string, string> = new Map<string, string>();\n\n initialize() {\n this.PER_AR_NUMBER.set(\"\\u06F0\", \"0\");\n this.PER_AR_NUMBER.set(\"\\u06F1\", \"1\");\n this.PER_AR_NUMBER.set(\"\\u06F2\", \"2\");\n this.PER_AR_NUMBER.set(\"\\u06F3\", \"3\");\n this.PER_AR_NUMBER.set(\"\\u06F4\", \"4\");\n this.PER_AR_NUMBER.set(\"\\u06F5\", \"5\");\n this.PER_AR_NUMBER.set(\"\\u06F6\", \"6\");\n this.PER_AR_NUMBER.set(\"\\u06F7\", \"7\");\n this.PER_AR_NUMBER.set(\"\\u06F8\", \"8\");\n this.PER_AR_NUMBER.set(\"\\u06F9\", \"9\");\n\n this.PER_AR_NUMBER.set(\"\\u0660\", \"0\");\n this.PER_AR_NUMBER.set(\"\\u0661\", \"1\");\n this.PER_AR_NUMBER.set(\"\\u0662\", \"2\");\n this.PER_AR_NUMBER.set(\"\\u0663\", \"3\");\n this.PER_AR_NUMBER.set(\"\\u0664\", \"4\");\n this.PER_AR_NUMBER.set(\"\\u0665\", \"5\");\n this.PER_AR_NUMBER.set(\"\\u0666\", \"6\");\n this.PER_AR_NUMBER.set(\"\\u0667\", \"7\");\n this.PER_AR_NUMBER.set(\"\\u0668\", \"8\");\n this.PER_AR_NUMBER.set(\"\\u0669\", \"9\");\n }\n\n inputManager: InputManager;\n\n constructor(private htmlInputElement: any, private options: RupiahMaskConfig) {\n this.inputManager = new InputManager(htmlInputElement);\n this.initialize()\n }\n\n addNumber(keyCode: number): void {\n const { decimal, precision, inputMode } = this.options;\n let keyChar = String.fromCharCode(keyCode);\n const isDecimalChar = keyChar === this.options.decimal;\n\n if (!this.rawValue) {\n this.rawValue = this.applyMask(false, keyChar);\n let selectionStart: number = 0;\n if (inputMode === RupiahMaskInputMode.NATURAL && precision > 0) {\n selectionStart = this.rawValue.indexOf(decimal);\n if (isDecimalChar) {\n selectionStart++;\n }\n }\n this.updateFieldValue(selectionStart);\n } else {\n let selectionStart = this.inputSelection.selectionStart;\n let selectionEnd = this.inputSelection.selectionEnd;\n const rawValueStart = this.rawValue.substring(0, selectionStart);\n let rawValueEnd = this.rawValue.substring(selectionEnd, this.rawValue.length);\n\n // In natural mode, replace decimals instead of shifting them.\n const inDecimalPortion = rawValueStart.indexOf(decimal) !== -1;\n if (inputMode === RupiahMaskInputMode.NATURAL && inDecimalPortion && selectionStart === selectionEnd) {\n rawValueEnd = rawValueEnd.substring(1);\n }\n\n const newValue = rawValueStart + keyChar + rawValueEnd;\n let nextSelectionStart = selectionStart + 1;\n const isDecimalOrThousands = isDecimalChar || keyChar === this.options.thousands;\n if (isDecimalOrThousands && keyChar === rawValueEnd[0]) {\n // If the cursor is just before the decimal or thousands separator and the user types the\n // decimal or thousands separator, move the cursor past it.\n nextSelectionStart++;\n } else if (!this.SINGLE_DIGIT_REGEX.test(keyChar)) {\n // Ignore other non-numbers.\n return;\n }\n\n this.rawValue = newValue;\n this.updateFieldValue(nextSelectionStart);\n }\n }\n\n applyMask(isNumber: boolean, rawValue: string, disablePadAndTrim = false): string {\n let { allowNegative, decimal, precision, prefix, suffix, thousands, min, max, inputMode } = this.options;\n\n rawValue = isNumber ? new Number(rawValue).toFixed(precision) : rawValue;\n let onlyNumbers = rawValue.replace(this.ONLY_NUMBERS_REGEX, \"\");\n\n if (!onlyNumbers && rawValue !== decimal) {\n return \"\";\n }\n\n if (inputMode === RupiahMaskInputMode.NATURAL && !isNumber && !disablePadAndTrim) {\n rawValue = this.padOrTrimPrecision(rawValue);\n onlyNumbers = rawValue.replace(this.ONLY_NUMBERS_REGEX, \"\");\n }\n\n let integerPart = onlyNumbers.slice(0, onlyNumbers.length - precision)\n .replace(/^\\u0660*/g, \"\")\n .replace(/^\\u06F0*/g, \"\")\n .replace(/^0*/g, \"\");\n\n if (integerPart == \"\") {\n integerPart = \"0\";\n }\n let integerValue = parseInt(integerPart);\n\n integerPart = integerPart.replace(/\\B(?=([0-9\\u0660-\\u0669\\u06F0-\\u06F9]{3})+(?![0-9\\u0660-\\u0669\\u06F0-\\u06F9]))/g, thousands);\n if (thousands && integerPart.startsWith(thousands)) {\n integerPart = integerPart.substring(1);\n }\n\n let newRawValue = integerPart;\n let decimalPart = onlyNumbers.slice(onlyNumbers.length - precision);\n let decimalValue = parseInt(decimalPart) || 0;\n\n let isNegative = rawValue.indexOf(\"-\") > -1;\n\n // Ensure max is at least as large as min.\n max = (this.isNullOrUndefined(max) || this.isNullOrUndefined(min)) ? max : Math.max(max!, min!);\n\n // Ensure precision number works well with more than 2 digits\n // 23 / 100... 233 / 1000 and so on\n const divideBy = Number('1'.padEnd(precision + 1, '0'));\n\n // Restrict to the min and max values.\n let newValue = integerValue + (decimalValue / divideBy);\n\n newValue = isNegative ? -newValue : newValue;\n if (!this.isNullOrUndefined(max) && newValue > max!) {\n return this.applyMask(true, max + '');\n } else if (!this.isNullOrUndefined(min) && newValue < min!) {\n return this.applyMask(true, min + '');\n }\n\n if (precision > 0) {\n if (newRawValue == \"0\" && decimalPart.length < precision) {\n newRawValue += decimal + \"0\".repeat(precision - 1) + decimalPart;\n } else {\n newRawValue += decimal + decimalPart;\n }\n }\n\n // let isZero = newValue == 0;\n let operator = (isNegative && allowNegative /*&& !isZero */) ? \"-\" : \"\";\n return operator + prefix + newRawValue + suffix;\n }\n\n padOrTrimPrecision(rawValue: string): string {\n let { decimal, precision } = this.options;\n\n let decimalIndex = rawValue.lastIndexOf(decimal);\n if (decimalIndex === -1) {\n decimalIndex = rawValue.length;\n rawValue += decimal;\n }\n\n let decimalPortion = rawValue.substring(decimalIndex).replace(this.ONLY_NUMBERS_REGEX, \"\");\n const actualPrecision = decimalPortion.length;\n if (actualPrecision < precision) {\n for (let i = actualPrecision; i < precision; i++) {\n decimalPortion += '0';\n }\n } else if (actualPrecision > precision) {\n decimalPortion = decimalPortion.substring(0, decimalPortion.length + precision - actualPrecision);\n }\n\n return rawValue.substring(0, decimalIndex) + decimal + decimalPortion;\n }\n\n clearMask(rawValue: string): number {\n if (this.isNullable() && rawValue === \"\")\n return 0;\n\n let value = (rawValue || \"0\").replace(this.options.prefix, \"\").replace(this.options.suffix, \"\");\n\n if (this.options.thousands) {\n value = value.replace(new RegExp(\"\\\\\" + this.options.thousands, \"g\"), \"\");\n }\n\n if (this.options.decimal) {\n value = value.replace(this.options.decimal, \".\");\n }\n\n this.PER_AR_NUMBER.forEach((val: string, key: string) => {\n const re = new RegExp(key, \"g\");\n value = value.replace(re, val);\n });\n return parseFloat(value);\n }\n\n changeToNegative(): void {\n if (this.options.allowNegative /*&& this.rawValue != \"\"*/ && this.rawValue.charAt(0) != \"-\" /*&& this.value != 0*/) {\n // Apply the mask to ensure the min and max values are enforced.\n this.rawValue = this.applyMask(false, \"-\" + (this.rawValue ? this.rawValue : '0'));\n }\n }\n\n changeToPositive(): void {\n // Apply the mask to ensure the min and max values are enforced.\n this.rawValue = this.applyMask(false, this.rawValue.replace(\"-\", \"\"));\n }\n\n removeNumber(keyCode: number): void {\n let { decimal, thousands, prefix, suffix, inputMode } = this.options;\n\n if (this.isNullable() && this.value == 0) {\n this.rawValue = '';\n return;\n }\n\n let selectionEnd = this.inputSelection.selectionEnd;\n let selectionStart = this.inputSelection.selectionStart;\n\n const suffixStart = this.rawValue.length - suffix.length;\n selectionEnd = Math.min(suffixStart, Math.max(selectionEnd, prefix.length));\n selectionStart = Math.min(suffixStart, Math.max(selectionStart, prefix.length));\n\n // Check if selection was entirely in the prefix or suffix.\n if (selectionStart === selectionEnd &&\n this.inputSelection.selectionStart !== this.inputSelection.selectionEnd) {\n this.updateFieldValue(selectionStart);\n return;\n }\n\n let decimalIndex = this.rawValue.indexOf(decimal);\n if (decimalIndex === -1) {\n decimalIndex = this.rawValue.length;\n }\n\n let shiftSelection = 0;\n let insertChars = '';\n\n const isCursorInDecimals = decimalIndex < selectionEnd;\n const isCursorImmediatelyAfterDecimalPoint = decimalIndex + 1 === selectionEnd;\n\n if (selectionEnd === selectionStart) {\n if (keyCode == 8) {\n if (selectionStart <= prefix.length) {\n return;\n }\n selectionStart--;\n\n // If previous char isn't a number, go back one more.\n if (!this.rawValue.substr(selectionStart, 1).match(/\\d/)) {\n selectionStart--;\n }\n\n // In natural mode, jump backwards when in decimal portion of number.\n if (inputMode === RupiahMaskInputMode.NATURAL && isCursorInDecimals) {\n shiftSelection = -1;\n // when removing a single whole number, replace it with 0\n if (isCursorImmediatelyAfterDecimalPoint && this.value < 10 && this.value > -10) {\n insertChars += '0';\n }\n }\n } else if (keyCode == 46 || keyCode == 63272) {\n if (selectionStart === suffixStart) {\n return;\n }\n selectionEnd++;\n\n // If next char isn't a number, go one more.\n if (!this.rawValue.substr(selectionStart, 1).match(/\\d/)) {\n selectionStart++;\n selectionEnd++;\n }\n }\n }\n\n // In natural mode, replace decimals with 0s.\n if (inputMode === RupiahMaskInputMode.NATURAL && selectionStart > decimalIndex) {\n const replacedDecimalCount = selectionEnd - selectionStart;\n for (let i = 0; i < replacedDecimalCount; i++) {\n insertChars += '0';\n }\n }\n\n let selectionFromEnd = this.rawValue.length - selectionEnd;\n this.rawValue = this.rawValue.substring(0, selectionStart) + insertChars + this.rawValue.substring(selectionEnd);\n\n // Remove leading thousand separator from raw value.\n const startChar = this.rawValue.substr(prefix.length, 1);\n if (startChar === thousands) {\n this.rawValue = this.rawValue.substring(0, prefix.length) + this.rawValue.substring(prefix.length + 1);\n selectionFromEnd = Math.min(selectionFromEnd, this.rawValue.length - prefix.length);\n }\n\n this.updateFieldValue(this.rawValue.length - selectionFromEnd + shiftSelection, true);\n }\n\n updateFieldValue(selectionStart?: number, disablePadAndTrim = false): void {\n let newRawValue = this.applyMask(false, this.rawValue || \"\", disablePadAndTrim);\n selectionStart = selectionStart == undefined ? this.rawValue.length : selectionStart;\n selectionStart = Math.max(this.options.prefix.length, Math.min(selectionStart, this.rawValue.length - this.options.suffix.length));\n this.inputManager.updateValueAndCursor(newRawValue, this.rawValue.length, selectionStart);\n }\n\n updateOptions(options: any): void {\n let value: number = this.value;\n this.options = options;\n this.value = value;\n }\n\n prefixLength(): any {\n return this.options.prefix.length;\n }\n\n suffixLength(): any {\n return this.options.suffix.length;\n }\n\n isNullable() {\n return this.options.nullable;\n }\n\n get canInputMoreNumbers(): boolean {\n return this.inputManager.canInputMoreNumbers;\n }\n\n get inputSelection(): any {\n return this.inputManager.inputSelection;\n }\n\n get rawValue(): string {\n return this.inputManager.rawValue;\n }\n\n set rawValue(value: string) {\n this.inputManager.rawValue = value;\n }\n\n get storedRawValue(): string {\n return this.inputManager.storedRawValue;\n }\n\n get value(): number {\n return this.clearMask(this.rawValue);\n }\n\n set value(value: number) {\n this.rawValue = this.applyMask(true, \"\" + value);\n }\n\n private isNullOrUndefined(value: any) {\n return value === null || value === undefined;\n }\n}","import { InputService } from \"./input.service\";\n\nexport class InputHandler {\n\n private inputService: InputService;\n private onModelChange!: Function;\n private onModelTouched!: Function;\n\n constructor(htmlInputElement: HTMLInputElement, options: any) {\n this.inputService = new InputService(htmlInputElement, options);\n }\n\n handleCut(event: any): void {\n setTimeout(() => {\n this.inputService.updateFieldValue();\n this.setValue(this.inputService.value);\n this.onModelChange(this.inputService.value);\n }, 0);\n }\n\n handleInput(event: any): void {\n let selectionStart = this.inputService.inputSelection.selectionStart;\n let keyCode = this.inputService.rawValue.charCodeAt(selectionStart - 1);\n let rawValueLength = this.inputService.rawValue.length;\n let storedRawValueLength = this.inputService.storedRawValue.length;\n\n if (Math.abs(rawValueLength - storedRawValueLength) != 1) {\n this.inputService.updateFieldValue(selectionStart);\n this.onModelChange(this.inputService.value);\n return;\n }\n\n // Restore the old value.\n this.inputService.rawValue = this.inputService.storedRawValue;\n\n if (rawValueLength < storedRawValueLength) {\n // Chrome Android seems to move the cursor in response to a backspace AFTER processing the\n // input event, so we need to wrap this in a timeout.\n this.timer(() => {\n // Move the cursor to just after the deleted value.\n this.inputService.updateFieldValue(selectionStart + 1);\n\n // Then backspace it.\n this.inputService.removeNumber(8);\n this.onModelChange(this.inputService.value);\n }, 0);\n }\n\n if (rawValueLength > storedRawValueLength) {\n // Move the cursor to just before the new value.\n this.inputService.updateFieldValue(selectionStart - 1);\n\n // Process the character like a keypress.\n this.handleKeypressImpl(keyCode);\n }\n }\n\n handleKeydown(event: any): void {\n let keyCode = event.which || event.charCode || event.keyCode;\n if (keyCode == 8 || keyCode == 46 || keyCode == 63272) {\n event.preventDefault();\n\n if (this.inputService.inputSelection.selectionStart <= this.inputService.prefixLength() &&\n this.inputService.inputSelection.selectionEnd >= this.inputService.rawValue.length - this.inputService.suffixLength()) {\n this.clearValue();\n } else {\n this.inputService.removeNumber(keyCode);\n this.onModelChange(this.inputService.value);\n }\n }\n }\n\n clearValue() {\n this.setValue(this.inputService.isNullable() ? 0 : 0);\n this.onModelChange(this.inputService.value);\n }\n\n handleKeypress(event: any): void {\n let keyCode = event.which || event.charCode || event.keyCode;\n event.preventDefault();\n if (keyCode === 97 && event.ctrlKey) {\n return;\n }\n\n this.handleKeypressImpl(keyCode);\n }\n\n private handleKeypressImpl(keyCode: number): void {\n switch (keyCode) {\n case undefined:\n case 9:\n case 13:\n return;\n case 43:\n this.inputService.changeToPositive();\n break;\n case 45:\n this.inputService.changeToNegative();\n break;\n default:\n if (this.inputService.canInputMoreNumbers) {\n let selectionRangeLength = Math.abs(this.inputService.inputSelection.selectionEnd - this.inputService.inputSelection.selectionStart);\n\n if (selectionRangeLength == this.inputService.rawValue.length) {\n this.setValue(0);\n }\n\n this.inputService.addNumber(keyCode);\n }\n break;\n }\n\n this.onModelChange(this.inputService.value);\n }\n\n handlePaste(event: any): void {\n setTimeout(() => {\n this.inputService.updateFieldValue();\n this.setValue(this.inputService.value);\n this.onModelChange(this.inputService.value);\n }, 1);\n }\n\n updateOptions(options: any): void {\n this.inputService.updateOptions(options);\n }\n\n getOnModelChange(): Function {\n return this.onModelChange;\n }\n\n setOnModelChange(callbackFunction: Function): void {\n this.onModelChange = callbackFunction;\n }\n\n getOnModelTouched(): Function {\n return this.onModelTouched;\n }\n\n setOnModelTouched(callbackFunction: Function) {\n this.onModelTouched = callbackFunction;\n }\n\n setValue(value: number): void {\n this.inputService.value = value;\n }\n\n /**\n * Passthrough to setTimeout that can be stubbed out in tests.\n */\n private timer(callback: () => void, delayMillis: number) {\n setTimeout(callback, delayMillis);\n }\n}","import {\n AfterViewInit,\n Directive,\n DoCheck,\n ElementRef,\n forwardRef,\n HostListener,\n Inject,\n KeyValueDiffer,\n KeyValueDiffers,\n Input,\n OnInit,\n Optional\n} from \"@angular/core\";\n\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from \"@angular/forms\";\nimport { RupiahMaskConfig, RUPIAH_MASK_CONFIG, RupiahMaskInputMode } from \"./rupiah-mask.config\";\nimport { InputHandler } from \"./input.handler\";\n\nexport const RUPIAHMASKDIRECTIVE_VALUE_ACCESSOR: any = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => RupiahMaskDirective),\n multi: true,\n};\n\n@Directive({\n selector: \"[rupiahMask]\",\n providers: [RUPIAHMASKDIRECTIVE_VALUE_ACCESSOR]\n})\nexport class RupiahMaskDirective implements AfterViewInit, ControlValueAccessor, DoCheck, OnInit {\n\n @Input() options: Partial<RupiahMaskConfig> = {};\n\n public inputHandler!: InputHandler;\n public keyValueDiffer: KeyValueDiffer<any, any>;\n\n public optionsTemplate: RupiahMaskConfig = {\n align: \"right\",\n allowNegative: true,\n allowZero: true,\n decimal: \".\",\n precision: 2,\n prefix: \"Rp \",\n suffix: \"\",\n thousands: \",\",\n nullable: false,\n inputMode: RupiahMaskInputMode.FINANCIAL\n };\n\n constructor(@Optional() @Inject(RUPIAH_MASK_CONFIG) private currencyMaskConfig: RupiahMaskConfig,\n private elementRef: ElementRef,\n private keyValueDiffers: KeyValueDiffers) {\n if (currencyMaskConfig) {\n this.optionsTemplate = currencyMaskConfig;\n }\n\n this.keyValueDiffer = keyValueDiffers.find({}).create();\n }\n\n ngAfterViewInit() {\n this.elementRef.nativeElement.style.textAlign = this.options && this.options.align ? this.options.align : this.optionsTemplate.align;\n }\n\n ngDoCheck() {\n if (this.keyValueDiffer.diff(this.options)) {\n this.elementRef.nativeElement.style.textAlign = this.options.align ? this.options.align : this.optionsTemplate.align;\n this.inputHandler.updateOptions((<any>Object).assign({}, this.optionsTemplate, this.options));\n }\n }\n\n ngOnInit() {\n this.inputHandler = new InputHandler(this.elementRef.nativeElement, (<any>Object).assign({}, this.optionsTemplate, this.options));\n }\n\n @HostListener(\"blur\", [\"$event\"])\n handleBlur(event: any) {\n this.inputHandler.getOnModelTouched().apply(event);\n }\n\n @HostListener(\"cut\", [\"$event\"])\n handleCut(event: any) {\n if (!this.isChromeAndroid()) {\n !this.isReadOnly() && this.inputHandler.handleCut(event);\n }\n }\n\n @HostListener(\"input\", [\"$event\"])\n handleInput(event: any) {\n if (this.isChromeAndroid()) {\n !this.isReadOnly() && this.inputHandler.handleInput(event);\n }\n }\n\n @HostListener(\"keydown\", [\"$event\"])\n handleKeydown(event: any) {\n if (!this.isChromeAndroid()) {\n !this.isReadOnly() && this.inputHandler.handleKeydown(event);\n }\n }\n\n @HostListener(\"keypress\", [\"$event\"])\n handleKeypress(event: any) {\n if (!this.isChromeAndroid()) {\n !this.isReadOnly() && this.inputHandler.handleKeypress(event);\n }\n }\n\n @HostListener(\"paste\", [\"$event\"])\n handlePaste(event: any) {\n if (!this.isChromeAndroid()) {\n !this.isReadOnly() && this.inputHandler.handlePaste(event);\n }\n }\n\n @HostListener(\"drop\", [\"$event\"])\n handleDrop(event: any) {\n if (!this.isChromeAndroid()) {\n event.preventDefault();\n }\n }\n\n isChromeAndroid(): boolean {\n return /chrome/i.test(navigator.userAgent) && /android/i.test(navigator.userAgent);\n }\n\n isReadOnly(): boolean {\n return this.elementRef.nativeElement.hasAttribute('readonly')\n }\n\n registerOnChange(callbackFunction: Function): void {\n this.inputHandler.setOnModelChange(callbackFunction);\n }\n\n registerOnTouched(callbackFunction: Function): void {\n this.inputHandler.setOnModelTouched(callbackFunction);\n }\n\n setDisabledState(value: boolean): void {\n this.elementRef.nativeElement.disabled = value;\n }\n\n writeValue(value: number): void {\n this.inputHandler.setValue(value);\n }\n}","import { Injectable } from \"@angular/core\";\n\n@Injectable({\n providedIn: 'root',\n})\nexport class RupiahService {\n public getTerbilang(value: number) {\n let valueString = String(value);\n let result = '';\n\n let i = 0;\n let j = 0;\n\n const angka: any = new Array('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0');\n const kata = new Array('', 'Satu', 'Dua', 'Tiga', 'Empat', 'Lima', 'Enam', 'Tujuh', 'Delapan', 'Sembilan');\n const tingkat = new Array('', 'Ribu', 'Juta', 'Milyar', 'Triliun');\n\n const panjang_valueString = valueString.length;\n\n /* pengujian panjang valueString */\n if (panjang_valueString > 15) {\n result = \"Diluar Batas\";\n return result;\n }\n\n /* mengambil angka-angka yang ada dalam valueString, dimasukkan ke dalam array */\n for (i = 1; i <= panjang_valueString; i++) {\n angka[i] = valueString.substr(-(i), 1);\n }\n\n i = 1;\n j = 0;\n result = \"\";\n\n /* mulai proses iterasi terhadap array angka */\n while (i <= panjang_valueString) {\n\n let subresult = \"\";\n let kata1 = \"\";\n let kata2 = \"\";\n let kata3 = \"\";\n\n /* untuk Ratusan */\n if (angka[i + 2] != \"0\") {\n if (angka[i + 2] == \"1\") {\n kata1 = \"Seratus\";\n } else {\n kata1 = kata[angka[i + 2]] + \" Ratus\";\n }\n }\n\n /* untuk Puluhan atau Belasan */\n if (angka[i + 1] != \"0\") {\n if (angka[i + 1] == \"1\") {\n if (angka[i] == \"0\") {\n kata2 = \"Sepuluh\";\n } else if (angka[i] == \"1\") {\n kata2 = \"Sebelas\";\n } else {\n kata2 = kata[angka[i]] + \" Belas\";\n }\n } else {\n kata2 = kata[angka[i + 1]] + \" Puluh\";\n }\n }\n\n /* untuk Satuan */\n if (angka[i] != \"0\") {\n if (angka[i + 1] != \"1\") {\n kata3 = kata[angka[i]];\n }\n }\n\n /* pengujian angka apakah tidak nol semua, lalu ditambahkan tingkat */\n if ((angka[i] != \"0\") || (angka[i + 1] != \"0\") || (angka[i + 2] != \"0\")) {\n subresult = kata1 + \" \" + kata2 + \" \" + kata3 + \" \" + tingkat[j] + \" \";\n }\n\n /* gabungkan variabe sub result (untuk Satu blok 3 angka) ke variabel result */\n result = subresult + result;\n i = i + 3;\n j = j + 1;\n\n }\n\n /* mengganti Satu Ribu jadi Seribu jika diperlukan */\n if ((angka[5] == \"0\") && (angka[6] == \"0\")) {\n result = result.replace(\"Satu Ribu\", \"Seribu\");\n }\n\n return result + \"Rupiah\";\n }\n}","\nimport { Pipe, PipeTransform } from '@angular/core';\nimport { RupiahService } from './rupiah.service';\n\n@Pipe({ name: 'terbilangPipe' })\nexport class TerbilangPipe implements PipeTransform {\n constructor(private rupiahService: RupiahService) {\n\n }\n\n public transform(value: number): string {\n if (value == undefined || value == null) {\n return '-';\n }\n\n return this.rupiahService.getTerbilang(value);\n }\n}","\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { formatCurrency, getCurrencySymbol } from '@angular/common';\nimport { registerLocaleData } from '@angular/common';\nimport localeID from '@angular/common/locales/id';\n\n@Pipe({ name: 'rupiahPipe' })\nexport class RupiahPipe implements PipeTransform {\n constructor() {\n registerLocaleData(localeID, 'id');\n }\n\n public transform(value: number, position: 'start' | 'end' | 'neutral' = 'start'): string {\n if (value == undefined || value == null) {\n return '-';\n }\n let price = formatCurrency(\n value,\n 'id-ID',\n '',\n 'IDR',\n '1.2-2',\n );\n\n let result = '';\n\n if (position === 'start') {\n result = 'Rp' + price;\n } else if (position === 'end') {\n result = price + ' Rupiah';\n } else {\n result = price;\n }\n return result;\n }\n}","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RupiahMaskDirective } from \"./rupiah-mask.directive\";\nimport { RUPIAH_MASK_CONFIG, RupiahMaskConfig } from \"./rupiah-mask.config\";\nimport { TerbilangPipe } from './terbilang.pipe';\nimport { RupiahPipe } from './rupiah.pipe';\n\n@NgModule({\n imports: [CommonModule, FormsModule],\n declarations: [RupiahMaskDirective, TerbilangPipe, RupiahPipe],\n exports: [RupiahMaskDirective, TerbilangPipe, RupiahPipe]\n})\nexport class NgxRupiahModule {\n static forRoot(config: RupiahMaskConfig): ModuleWithProviders<NgxRupiahModule> {\n return {\n ngModule: NgxRupiahModule,\n providers: [{\n provide: RUPIAH_MASK_CONFIG,\n useValue: config,\n }]\n }\n }\n}","/*\n * Public API Surface of ngx-rupiah\n */\n\nexport * from './lib/rupiah-mask.config';\nexport * from './lib/rupiah-mask.directive';\nexport * from './lib/rupiah-mask.module';\nexport * from './lib/input.handler';\nexport * from './lib/input.manager';\nexport * from './lib/input.service';\nexport * from './lib/rupiah.service';\nexport * from './lib/terbilang.pipe';\nexport * from './lib/rupiah.pipe';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.RupiahService"],"mappings":"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