1 /*jshint node:true, indent:2, curly:true, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
2 regexp:true, undef:true, trailing:true, white:true */
3 /*global XT:true, XV:true, XM:true, Globalize:true, enyo:true, _:true */
8 The widget is created with an attr value that is an object composed of two key-values pairs.
9 These pairs include the amount (localValue or baseValue) and the currency attribute strings from the model.
10 The workspace replaces the attribute name string value
11 The localValue key should be used if the model stores the local currency and the baseValue key should
12 be used if the models stores the base currency.
13 The effective attribute should contain the date by which calculations
16 name: "XV.MoneyWidget",
17 kind: "XV.NumberWidget",
18 classes: "xv-moneywidget",
20 scale: XT.MONEY_SCALE,
21 localValue: null, // {Number} the number in the user field
22 baseValue: null, // {Number} the amount in the base currency
25 currencyDisabled: false,
26 currencyShowing: true,
29 isEditableProperty: "localValue" // The property mapped to an attribute that checks whether editbale
32 onValueChange: "pickerChanged" // intercept picker events
36 {kind: "FittableColumns", components: [
37 {name: "label", content: "", classes: "xv-label"},
38 {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
40 {name: "input", kind: "onyx.Input",
41 onchange: "inputChanged", onkeydown: "keyDown"}
43 {name: "picker", kind: "XV.CurrencyPicker", showLabel: false}
45 {kind: "FittableColumns", name: "basePanel", showing: false,
47 {name: "spacer", content: "", classes: "xv-label"},
48 {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
50 {name: "baseAmountLabel", classes: "xv-money-label"}
52 {kind: "onyx.InputDecorator", classes: "xv-input-decorator, xv-currency-label",
54 {name: "baseCurrencyLabel"}
60 Set the base price into the base amount label
62 baseValueChanged: function () {
63 var localMode = this.getLocalMode(),
68 baseValue = this.getBaseValue();
69 scale = this.getScale();
70 content = baseValue || baseValue === 0 ?
71 Globalize.format(baseValue, "n" + scale) : "";
72 this.$.baseAmountLabel.setContent(content);
79 If the effective date is provided, the fixedRate is set and the
83 this.inherited(arguments);
85 var baseCurrency = XT.baseCurrency();
87 this.bubble("onNotify", {message: "_baseCurrencyMustBeSet".loc()});
90 this.setEffective(new Date());
91 this.setCurrency(baseCurrency);
92 this.setLocalValue(0);
93 this.$.baseCurrencyLabel.setContent(baseCurrency.get('abbreviation'));
95 // the currency picker may be disabled or hidden on creation in certain situations
96 this.currencyDisabledChanged();
97 this.currencyShowingChanged();
99 // this is for styling of the picker since the PickerWidget has a built in
101 this.$.picker.$.inputWrapper.removeClass("onyx-input-decorator");
103 // set the "mode" of this widget, whether or not it directly saves the local
104 // value to the model, or if it converts it to and from the base value.
105 this.setLocalMode(_.has(this.getAttr(), "localValue"));
108 clear: function (options) {
109 this.setValue({localValue: null}, options);
112 currencyChanged: function () {
113 this.$.picker.setValue(this.getCurrency(), {silent: true});
117 currencyDisabledChanged: function () {
118 this.$.picker.setDisabled(this.getCurrencyDisabled());
121 currencyShowingChanged: function () {
122 this.$.picker.setShowing(this.getCurrencyShowing());
126 This setDisabled function is all or nothing for both widgets
129 disabledChanged: function () {
130 var disabled = this.getDisabled(),
131 currencyDisabled = this.getCurrencyDisabled();
132 this.$.input.setDisabled(disabled);
133 this.$.picker.setDisabled(disabled || currencyDisabled);
134 this.$.label.addRemoveClass("disabled", this.getDisabled());
138 @todo Document the labelChanged method.
140 labelChanged: function () {
141 var attr = this.getAttr(),
142 valueAttr = attr.localValue || attr.baseValue;
143 var label = (this.getLabel() || ("_" + valueAttr || "").loc());
144 this.$.label.setContent(label + ":");
147 effectiveChanged: function () {
151 localValueChanged: function () {
152 this.valueChanged(this.getLocalValue()); // forward to XV.Number default for formatting
156 recalculate: function () {
157 var localMode = this.getLocalMode(),
158 value = localMode ? this.getLocalValue() : this.getBaseValue(),
159 request = localMode ? "toBase" : "fromBase",
160 setter = localMode ? "setBaseValue" : "setLocalValue",
161 currency = this.getCurrency(),
162 effective = this.getEffective(),
163 showing = localMode && _.isDate(effective) && currency &&
164 !currency.get("isBase"),
169 if (!currency || !effective) { return; }
171 // Keep track of requests, we'll ignore stale ones
172 this._counter = _.isNumber(this._counter) ? this._counter + 1 : 0;
175 if (_.isNumber(value)) {
176 if (currency.get("isBase")) {
177 // we're at base, so just set the fields with the base value we have
180 options.success = function (calcValue) {
181 // I only smell freshness
182 if (i < that._counter) { return; }
183 that[setter](calcValue);
185 currency[request](value, effective, options);
187 } else { // amount is null
191 this.$.basePanel.setShowing(showing);
194 setDisabled: function (isDisabled) {
195 this.inherited(arguments);
196 this.$.picker.setDisabled(isDisabled || this.getCurrencyDisabled());
200 This setValue function handles a value which is an
201 object potentially consisting of multiple key/value pairs for the
202 amount and currency controls.
204 @param {Object} Value
205 @param {Object} [value.currency] Currency
206 @param {Date} [value.effective] Effective date
207 @param {Number} [value.localValue] Local value
208 @param {Number} [value.baseValue] Base value
210 setValue: function (value, options) {
211 options = options || {};
212 var attr = this.getAttr(),
214 keys = _.keys(value),
219 // Loop through the properties and update calling
220 // appropriate "set" functions and add to "changed"
221 // object if applicable
222 for (i = 0; i < keys.length; i++) {
224 set = 'set' + key.slice(0, 1).toUpperCase() + key.slice(1);
225 this[set](value[key]);
227 changed[attr[key]] = value[key];
231 // Bubble changes if applicable
232 if (!_.isEmpty(changed) && !options.silent) {
233 this.doValueChange({value: changed});
237 inputChanged: function (inSender, inEvent) {
238 var input = this.$.input.getValue(),
239 value = this.validate(input),
240 prop = this.getLocalMode() ? 'localValue' : 'baseValue',
242 if (value !== false) {
250 this.valueChanged("");
255 Intercept the valueChanged event from picker.
257 pickerChanged: function (inSender, inEvent) {
259 if (inEvent.originator.name === "picker") {
260 value = XM.currencies.get(inEvent.value);
261 this.setValue({currency: value});