Skip to content

Instantly share code, notes, and snippets.

@lennyburdette
Last active April 2, 2020 19:47
Show Gist options
  • Save lennyburdette/c2c30a0f83345f42cc650f3414cb4776 to your computer and use it in GitHub Desktop.
Save lennyburdette/c2c30a0f83345f42cc650f3414cb4776 to your computer and use it in GitHub Desktop.
money-input
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { format, parse } from '../helpers/format';
import { scheduleOnce } from '@ember/runloop';
export default class extends Component {
@tracked currencyCode = 'USD';
@tracked formattedValue;
@tracked previousRawValue;
@action
changeValue({ target }) {
const { value, selectionStart, selectionEnd } = target;
if (value.match(/[^\d\.,]/)) {
target.value = this.previousRawValue;
return;
}
this.previousRawValue = value;
const parsedValue = parse(target.value, this.currencyCode);
this.formattedValue = format(parsedValue, this.currencyCode);
// const selectionStart = target.selectionStart;
// scheduleOnce('afterRender', () => {
// target.setSelectionRange(selectionStart, selectionStart);
// });
this.args.onChange(parsedValue);
}
@action
changeCurrency(currency) {
this.currencyCode = currency;
this.formattedValue = format(this.args.cents, this.currencyCode);
this.args.onChange(value);
}
}
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
export default class ApplicationController extends Controller {
@tracked cents;
}
import { helper } from '@ember/component/helper';
export function format(cents, currencyCode) {
switch (currencyCode) {
case 'USD': return formatUSD(cents);
default: return cents;
}
}
export function parse(formatted, currencyCode) {
switch (currencyCode) {
case 'USD': return parseUSD(formatted);
default: return formatted ? +formatted : formatted;
}
}
export default helper(function format(params/*, hash*/) {
return params;
});
export function formatUSD(n) {
if (n == null) {
return '';
}
switch (`${n}`.length) {
case 1: return `00.0${n}`;
case 2: return `00.${n}`;
case 3:
case 4:
case 5: {
const d = Math.floor(n / 100);
const c = n % 100;
return [`${d}`.padStart(2, '0'), `${c}`.padStart(2, '0')].join('.');
}
case 6:
case 7:
case 8: {
const k = Math.floor(n / 100000);
const d = Math.floor((n % 100000) / 100);
const c = n % 100;
return [
`${k}`,
',',
`${d}`.padStart(2, '0'),
'.',
`${c}`.padStart(2, '0')
].join('');
}
case 9:
case 10:
case 11: {
const m = Math.floor(n / 100000000);
const k = Math.floor((n % 100000000) / 100000);
const d = Math.floor((n % 100000) / 100);
const c = n % 100;
return [
`${m}`,
',',
`${k}`,
',',
`${d}`.padStart(2, '0'),
'.',
`${c}`.padStart(2, '0')
].join('');
}
case 12:
case 13:
case 14: {
const cm = Math.floor(n / 100000000000);
const m = Math.floor((n % 100000000000) / 100000000);
const k = Math.floor((n % 100000000) / 100000);
const d = Math.floor((n % 100000) / 100);
const c = n % 100;
return [
`${cm}`,
',',
`${m}`,
',',
`${k}`,
',',
`${d}`.padStart(2, '0'),
'.',
`${c}`.padStart(2, '0')
].join('');
}
default: return `${n}`;
}
}
export function parseUSD(s) {
const n = parseInt(
s.replace(/[\.,]/g, '').replace(/^0+/, '')
, 10)
return isNaN(n) ? 0 : n;
}
<div>{{this.cents}}</div>
<MoneyInput @cents={{this.cents}} @onChange={{fn (mut this.cents)}} />
{{this.currencyCode}}
<input
value={{this.formattedValue}}
{{on "input" this.changeValue}}
/>
<button {{on "click" (fn this.changeCurrency 'USD')}}>USD</button>
<button {{on "click" (fn this.changeCurrency 'JPY')}}>JPY</button>
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { formatUSD, parseUSD } from '../../../helpers/format';
module('helpers/format', function(hooks) {
setupRenderingTest(hooks);
test('formatUSD', async function(assert) {
assert.equal(formatUSD(1), '00.01');
assert.equal(formatUSD(12), '00.12');
assert.equal(formatUSD(123), '01.23');
assert.equal(formatUSD(1234), '12.34');
assert.equal(formatUSD(12345), '123.45');
assert.equal(formatUSD(123456), '1,234.56');
assert.equal(formatUSD(1234567), '12,345.67');
assert.equal(formatUSD(12345678), '123,456.78');
});
test('formatUSD', async function(assert) {
assert.equal(parseUSD('00.01'), 1);
assert.equal(parseUSD('00.12'), 12);
assert.equal(parseUSD('01.23'), 123);
assert.equal(parseUSD('12.34'), 1234);
assert.equal(parseUSD('123.45'), 12345);
assert.equal(parseUSD('1,234.56'), 123456);
assert.equal(parseUSD('12,345.67'), 1234567);
assert.equal(parseUSD('123,456.78'), 12345678);
});
});
import Application from '../app';
import config from '../config/environment';
import { setApplication } from '@ember/test-helpers';
import { assign } from '@ember/polyfills';
import { start } from 'ember-qunit';
let attributes = {
rootElement: '#test-root',
autoboot: false
};
attributes = assign(attributes, config.APP);
let application = Application.create(attributes);
setApplication(application);
start();
{
"version": "0.17.0",
"EmberENV": {
"FEATURES": {},
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false,
"_APPLICATION_TEMPLATE_WRAPPER": true,
"_JQUERY_INTEGRATION": true
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js",
"ember": "3.17.0",
"ember-template-compiler": "3.17.0",
"ember-testing": "3.17.0"
},
"addons": {
"@glimmer/component": "1.0.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment