3 * @class Roo.bootstrap.MoneyField
4 * @extends Roo.bootstrap.ComboBox
5 * Bootstrap MoneyField class
8 * Create a new MoneyField.
9 * @param {Object} config Configuration options
12 Roo.bootstrap.MoneyField = function(config) {
14 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
18 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
21 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
25 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
27 decimalSeparator : ".",
29 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39 minValue : Number.NEGATIVE_INFINITY,
41 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
43 maxValue : Number.MAX_VALUE,
45 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
47 minText : "The minimum value for this field is {0}",
49 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
51 maxText : "The maximum value for this field is {0}",
53 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
54 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
56 nanText : "{0} is not a valid number",
58 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
69 getAutoCreate : function()
71 var align = this.labelAlign || this.parentLabelAlign();
83 cls : 'form-control roo-money-amount-input',
84 autocomplete: 'new-password'
88 input.name = this.name;
92 input.disabled = true;
95 var clg = 12 - this.inputlg;
96 var cmd = 12 - this.inputmd;
97 var csm = 12 - this.inputsm;
98 var cxs = 12 - this.inputxs;
102 cls : 'row roo-money-field',
106 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
110 cls: 'roo-select2-container input-group',
114 cls : 'form-control roo-money-currency-input',
115 autocomplete: 'new-password'
119 cls : 'input-group-addon',
133 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
137 cls: this.hasFeedback ? 'has-feedback' : '',
148 if (this.fieldLabel.length) {
151 tooltip: 'This field is required'
157 cls: 'control-label',
163 html: this.fieldLabel
166 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
172 if(this.indicatorpos == 'right') {
173 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
180 if(align == 'left') {
188 if(this.labelWidth > 12){
189 label.style = "width: " + this.labelWidth + 'px';
191 if(this.labelWidth < 13 && this.labelmd == 0){
192 this.labelmd = this.labelWidth;
194 if(this.labellg > 0){
195 label.cls += ' col-lg-' + this.labellg;
196 input.cls += ' col-lg-' + (12 - this.labellg);
198 if(this.labelmd > 0){
199 label.cls += ' col-md-' + this.labelmd;
200 container.cls += ' col-md-' + (12 - this.labelmd);
202 if(this.labelsm > 0){
203 label.cls += ' col-sm-' + this.labelsm;
204 container.cls += ' col-sm-' + (12 - this.labelsm);
206 if(this.labelxs > 0){
207 label.cls += ' col-xs-' + this.labelxs;
208 container.cls += ' col-xs-' + (12 - this.labelxs);
220 ['xs','sm','md','lg'].map(function(size){
221 if (settings[size]) {
222 cfg.cls += ' col-' + size + '-' + settings[size];
230 initEvents : function()
232 this.indicator = this.indicatorEl();
234 this.initCurrencyEvent();
236 this.initNumberEvent();
240 initCurrencyEvent : function()
243 throw "can not find store for combo";
246 this.store = Roo.factory(this.store, Roo.data);
247 this.store.parent = this;
251 this.triggerEl = this.el.select('.input-group-addon', true).first();
253 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
255 this.currencyEl = this.el.select('.roo-money-currency-input', true).first();
257 this.amountEl = this.el.select('.roo-money-amount-input', true).first();
262 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
263 _this.list.setWidth(lw);
266 this.list.on('mouseover', this.onViewOver, this);
267 this.list.on('mousemove', this.onViewMove, this);
268 this.list.on('scroll', this.onViewScroll, this);
271 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
274 this.view = new Roo.View(this.list, this.tpl, {
275 singleSelect:true, store: this.store, selectedClass: this.selectedClass
278 this.view.on('click', this.onViewClick, this);
280 this.store.on('beforeload', this.onBeforeLoad, this);
281 this.store.on('load', this.onLoad, this);
282 this.store.on('loadexception', this.onLoadException, this);
284 this.keyNav = new Roo.KeyNav(this.currencyEl, {
286 this.inKeyMode = true;
290 "down" : function(e){
291 if(!this.isExpanded()){
292 this.onTriggerClick();
294 this.inKeyMode = true;
299 "enter" : function(e){
302 if(this.fireEvent("specialkey", this, e)){
303 this.onViewClick(false);
316 if(this.fireEvent("specialkey", this, e)){
317 this.onViewClick(false);
325 doRelay : function(foo, bar, hname){
326 if(hname == 'down' || this.scope.isExpanded()){
327 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
337 initNumberEvent : function(e)
339 this.inputEl().on("keydown" , this.fireKey, this);
340 this.inputEl().on("focus", this.onFocus, this);
341 this.inputEl().on("blur", this.onBlur, this);
343 this.inputEl().relayEvent('keyup', this);
346 this.indicator.addClass('invisible');
349 this.originalValue = this.getValue();
351 if(this.validationEvent == 'keyup'){
352 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
353 this.inputEl().on('keyup', this.filterValidation, this);
355 else if(this.validationEvent !== false){
356 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
359 if(this.selectOnFocus){
360 this.on("focus", this.preFocus, this);
363 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
364 this.inputEl().on("keypress", this.filterKeys, this);
366 this.inputEl().relayEvent('keypress', this);
369 var allowed = "0123456789";
371 if(this.allowDecimals){
372 allowed += this.decimalSeparator;
375 if(this.allowNegative){
379 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
381 var keyPress = function(e){
385 var c = e.getCharCode();
388 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
389 allowed.indexOf(String.fromCharCode(c)) === -1
395 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
399 if(allowed.indexOf(String.fromCharCode(c)) === -1){
404 this.inputEl().on("keypress", keyPress, this);
408 onTriggerClick : function(e)
415 this.loadNext = false;
417 if(this.isExpanded()){
422 this.hasFocus = true;
424 if(this.triggerAction == 'all') {
425 this.doQuery(this.allQuery, true);
429 this.doQuery(this.getRawValue());
432 getCurrency : function()
434 var v = this.currencyEl.getValue();
439 restrictHeight : function()
441 this.list.alignTo(this.currencyEl, this.listAlign);
442 this.list.alignTo(this.currencyEl, this.listAlign);
445 onViewClick : function(view, doFocus, el, e)
447 var index = this.view.getSelectedIndexes()[0];
449 var r = this.store.getAt(index);
452 this.onSelect(r, index);
456 onSelect : function(record, index){
458 if(this.fireEvent('beforeselect', this, record, index) !== false){
460 this.setFromCurrencyData(index > -1 ? record.data : false);
464 this.fireEvent('select', this, record, index);
468 setFromCurrencyData : function(o)
472 this.lastCurrency = o;
474 if (this.currencyField) {
475 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
477 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
480 this.lastSelectionText = currency;
482 this.setCurrency(currency);
485 setFromData : function(o)
489 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
491 this.setFromCurrencyData(c);
496 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
498 Roo.log('no value set for '+ (this.name ? this.name : this.id));
501 this.setValue(value);
505 setCurrency : function(v)
507 this.currencyValue = v;
510 this.currencyEl.dom.value = (v === null || v === undefined ? '' : v);
515 setValue : function(v)
517 v = this.fixPrecision(v);
519 v = String(v).replace(".", this.decimalSeparator);
524 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
529 getRawValue : function()
531 var v = this.inputEl().getValue();
536 getValue : function()
538 return this.fixPrecision(this.parseValue(this.getRawValue()));
541 parseValue : function(value)
543 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
544 return isNaN(value) ? '' : value;
547 fixPrecision : function(value)
549 var nan = isNaN(value);
551 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
552 return nan ? '' : value;
555 return parseFloat(value).toFixed(this.decimalPrecision);
558 decimalPrecisionFcn : function(v)
560 return Math.floor(v);
563 validateValue : function(value)
565 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
569 var num = this.parseValue(value);
572 this.markInvalid(String.format(this.nanText, value));
576 if(num < this.minValue){
577 this.markInvalid(String.format(this.minText, this.minValue));
581 if(num > this.maxValue){
582 this.markInvalid(String.format(this.maxText, this.maxValue));
589 validate : function()
596 var currency = this.getCurrency();
598 if(this.validateValue(this.getRawValue()) && currency.length){
612 beforeBlur : function()
618 var v = this.parseValue(this.getRawValue());
629 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
630 //this.el.removeClass(this.focusClass);
633 this.hasFocus = false;
635 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
639 var v = this.getValue();
641 if(String(v) !== String(this.startValue)){
642 this.fireEvent('change', this, v, this.startValue);
645 this.fireEvent("blur", this);
650 return this.amountEl ? this.amountEl : this.el.select('.roo-money-amount-input', true).first();