MOVED Roo/bootstrap/PhoneInput.js to Roo/bootstrap/form/PhoneInput.js
authorAlan Knowles <alan@roojs.com>
Fri, 30 Jul 2021 07:10:04 +0000 (15:10 +0800)
committerAlan Knowles <alan@roojs.com>
Fri, 30 Jul 2021 07:10:04 +0000 (15:10 +0800)
MOVED Roo/bootstrap/PhoneInputData.js to Roo/bootstrap/form/PhoneInputData.js
Roo/bootstrap/PhoneInput.js
Roo/bootstrap/PhoneInputData.js
MOVED Roo/bootstrap/NumberField.js to Roo/bootstrap/form/NumberField.js
Roo/bootstrap/NumberField.js
MOVED Roo/bootstrap/MoneyField.js to Roo/bootstrap/form/MoneyField.js
MOVED Roo/bootstrap/MonthField.js to Roo/bootstrap/form/MonthField.js
Roo/bootstrap/MoneyField.js
Roo/bootstrap/MonthField.js

Roo/bootstrap/form/MoneyField.js [new file with mode: 0644]
Roo/bootstrap/form/MonthField.js [new file with mode: 0644]
Roo/bootstrap/form/NumberField.js [new file with mode: 0644]
Roo/bootstrap/form/PhoneInput.js [new file with mode: 0644]
Roo/bootstrap/form/PhoneInputData.js [new file with mode: 0644]

diff --git a/Roo/bootstrap/form/MoneyField.js b/Roo/bootstrap/form/MoneyField.js
new file mode 100644 (file)
index 0000000..391894d
--- /dev/null
@@ -0,0 +1,722 @@
+
+/**
+ * @class Roo.bootstrap.MoneyField
+ * @extends Roo.bootstrap.ComboBox
+ * Bootstrap MoneyField class
+ * 
+ * @constructor
+ * Create a new MoneyField.
+ * @param {Object} config Configuration options
+ */
+
+Roo.bootstrap.MoneyField = function(config) {
+    
+    Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
+    
+};
+
+Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
+    
+    /**
+     * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
+     */
+    allowDecimals : true,
+    /**
+     * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
+     */
+    decimalSeparator : ".",
+    /**
+     * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
+     */
+    decimalPrecision : 0,
+    /**
+     * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
+     */
+    allowNegative : true,
+    /**
+     * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
+     */
+    allowZero: true,
+    /**
+     * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
+     */
+    minValue : Number.NEGATIVE_INFINITY,
+    /**
+     * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
+     */
+    maxValue : Number.MAX_VALUE,
+    /**
+     * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
+     */
+    minText : "The minimum value for this field is {0}",
+    /**
+     * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
+     */
+    maxText : "The maximum value for this field is {0}",
+    /**
+     * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
+     * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
+     */
+    nanText : "{0} is not a valid number",
+    /**
+     * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
+     */
+    castInt : true,
+    /**
+     * @cfg {String} defaults currency of the MoneyField
+     * value should be in lkey
+     */
+    defaultCurrency : false,
+    /**
+     * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
+     */
+    thousandsDelimiter : false,
+    /**
+     * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
+     */
+    max_length: false,
+    
+    inputlg : 9,
+    inputmd : 9,
+    inputsm : 9,
+    inputxs : 6,
+     /**
+     * @cfg {Roo.data.Store} store  Store to lookup currency??
+     */
+    store : false,
+    
+    getAutoCreate : function()
+    {
+        var align = this.labelAlign || this.parentLabelAlign();
+        
+        var id = Roo.id();
+
+        var cfg = {
+            cls: 'form-group',
+            cn: []
+        };
+
+        var input =  {
+            tag: 'input',
+            id : id,
+            cls : 'form-control roo-money-amount-input',
+            autocomplete: 'new-password'
+        };
+        
+        var hiddenInput = {
+            tag: 'input',
+            type: 'hidden',
+            id: Roo.id(),
+            cls: 'hidden-number-input'
+        };
+        
+        if(this.max_length) {
+            input.maxlength = this.max_length; 
+        }
+        
+        if (this.name) {
+            hiddenInput.name = this.name;
+        }
+
+        if (this.disabled) {
+            input.disabled = true;
+        }
+
+        var clg = 12 - this.inputlg;
+        var cmd = 12 - this.inputmd;
+        var csm = 12 - this.inputsm;
+        var cxs = 12 - this.inputxs;
+        
+        var container = {
+            tag : 'div',
+            cls : 'row roo-money-field',
+            cn : [
+                {
+                    tag : 'div',
+                    cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
+                    cn : [
+                        {
+                            tag : 'div',
+                            cls: 'roo-select2-container input-group',
+                            cn: [
+                                {
+                                    tag : 'input',
+                                    cls : 'form-control roo-money-currency-input',
+                                    autocomplete: 'new-password',
+                                    readOnly : 1,
+                                    name : this.currencyName
+                                },
+                                {
+                                    tag :'span',
+                                    cls : 'input-group-addon',
+                                    cn : [
+                                        {
+                                            tag: 'span',
+                                            cls: 'caret'
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
+                    cn : [
+                        {
+                            tag: 'div',
+                            cls: this.hasFeedback ? 'has-feedback' : '',
+                            cn: [
+                                input
+                            ]
+                        }
+                    ]
+                }
+            ]
+            
+        };
+        
+        if (this.fieldLabel.length) {
+            var indicator = {
+                tag: 'i',
+                tooltip: 'This field is required'
+            };
+
+            var label = {
+                tag: 'label',
+                'for':  id,
+                cls: 'control-label',
+                cn: []
+            };
+
+            var label_text = {
+                tag: 'span',
+                html: this.fieldLabel
+            };
+
+            indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
+            label.cn = [
+                indicator,
+                label_text
+            ];
+
+            if(this.indicatorpos == 'right') {
+                indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
+                label.cn = [
+                    label_text,
+                    indicator
+                ];
+            }
+
+            if(align == 'left') {
+                container = {
+                    tag: 'div',
+                    cn: [
+                        container
+                    ]
+                };
+
+                if(this.labelWidth > 12){
+                    label.style = "width: " + this.labelWidth + 'px';
+                }
+                if(this.labelWidth < 13 && this.labelmd == 0){
+                    this.labelmd = this.labelWidth;
+                }
+                if(this.labellg > 0){
+                    label.cls += ' col-lg-' + this.labellg;
+                    input.cls += ' col-lg-' + (12 - this.labellg);
+                }
+                if(this.labelmd > 0){
+                    label.cls += ' col-md-' + this.labelmd;
+                    container.cls += ' col-md-' + (12 - this.labelmd);
+                }
+                if(this.labelsm > 0){
+                    label.cls += ' col-sm-' + this.labelsm;
+                    container.cls += ' col-sm-' + (12 - this.labelsm);
+                }
+                if(this.labelxs > 0){
+                    label.cls += ' col-xs-' + this.labelxs;
+                    container.cls += ' col-xs-' + (12 - this.labelxs);
+                }
+            }
+        }
+
+        cfg.cn = [
+            label,
+            container,
+            hiddenInput
+        ];
+        
+        var settings = this;
+
+        ['xs','sm','md','lg'].map(function(size){
+            if (settings[size]) {
+                cfg.cls += ' col-' + size + '-' + settings[size];
+            }
+        });
+        
+        return cfg;
+    },
+    
+    initEvents : function()
+    {
+        this.indicator = this.indicatorEl();
+        
+        this.initCurrencyEvent();
+        
+        this.initNumberEvent();
+    },
+    
+    initCurrencyEvent : function()
+    {
+        if (!this.store) {
+            throw "can not find store for combo";
+        }
+        
+        this.store = Roo.factory(this.store, Roo.data);
+        this.store.parent = this;
+        
+        this.createList();
+        
+        this.triggerEl = this.el.select('.input-group-addon', true).first();
+        
+        this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
+        
+        var _this = this;
+        
+        (function(){
+            var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
+            _this.list.setWidth(lw);
+        }).defer(100);
+        
+        this.list.on('mouseover', this.onViewOver, this);
+        this.list.on('mousemove', this.onViewMove, this);
+        this.list.on('scroll', this.onViewScroll, this);
+        
+        if(!this.tpl){
+            this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
+        }
+        
+        this.view = new Roo.View(this.list, this.tpl, {
+            singleSelect:true, store: this.store, selectedClass: this.selectedClass
+        });
+        
+        this.view.on('click', this.onViewClick, this);
+        
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
+        
+        this.keyNav = new Roo.KeyNav(this.currencyEl(), {
+            "up" : function(e){
+                this.inKeyMode = true;
+                this.selectPrev();
+            },
+
+            "down" : function(e){
+                if(!this.isExpanded()){
+                    this.onTriggerClick();
+                }else{
+                    this.inKeyMode = true;
+                    this.selectNext();
+                }
+            },
+
+            "enter" : function(e){
+                this.collapse();
+                
+                if(this.fireEvent("specialkey", this, e)){
+                    this.onViewClick(false);
+                }
+                
+                return true;
+            },
+
+            "esc" : function(e){
+                this.collapse();
+            },
+
+            "tab" : function(e){
+                this.collapse();
+                
+                if(this.fireEvent("specialkey", this, e)){
+                    this.onViewClick(false);
+                }
+                
+                return true;
+            },
+
+            scope : this,
+
+            doRelay : function(foo, bar, hname){
+                if(hname == 'down' || this.scope.isExpanded()){
+                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
+                }
+                return true;
+            },
+
+            forceKeyDown: true
+        });
+        
+        this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
+        
+    },
+    
+    initNumberEvent : function(e)
+    {
+        this.inputEl().on("keydown" , this.fireKey,  this);
+        this.inputEl().on("focus", this.onFocus,  this);
+        this.inputEl().on("blur", this.onBlur,  this);
+        
+        this.inputEl().relayEvent('keyup', this);
+        
+        if(this.indicator){
+            this.indicator.addClass('invisible');
+        }
+        this.originalValue = this.getValue();
+        
+        if(this.validationEvent == 'keyup'){
+            this.validationTask = new Roo.util.DelayedTask(this.validate, this);
+            this.inputEl().on('keyup', this.filterValidation, this);
+        }
+        else if(this.validationEvent !== false){
+            this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
+        }
+        
+        if(this.selectOnFocus){
+            this.on("focus", this.preFocus, this);
+            
+        }
+        if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
+            this.inputEl().on("keypress", this.filterKeys, this);
+        } else {
+            this.inputEl().relayEvent('keypress', this);
+        }
+        
+        var allowed = "0123456789";
+        
+        if(this.allowDecimals){
+            allowed += this.decimalSeparator;
+        }
+        
+        if(this.allowNegative){
+            allowed += "-";
+        }
+        
+        if(this.thousandsDelimiter) {
+            allowed += ",";
+        }
+        
+        this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
+        
+        var keyPress = function(e){
+            
+            var k = e.getKey();
+            
+            var c = e.getCharCode();
+            
+            if(
+                    (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
+                    allowed.indexOf(String.fromCharCode(c)) === -1
+            ){
+                e.stopEvent();
+                return;
+            }
+            
+            if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
+                return;
+            }
+            
+            if(allowed.indexOf(String.fromCharCode(c)) === -1){
+                e.stopEvent();
+            }
+        };
+        
+        this.inputEl().on("keypress", keyPress, this);
+        
+    },
+    
+    onTriggerClick : function(e)
+    {   
+        if(this.disabled){
+            return;
+        }
+        
+        this.page = 0;
+        this.loadNext = false;
+        
+        if(this.isExpanded()){
+            this.collapse();
+            return;
+        }
+        
+        this.hasFocus = true;
+        
+        if(this.triggerAction == 'all') {
+            this.doQuery(this.allQuery, true);
+            return;
+        }
+        
+        this.doQuery(this.getRawValue());
+    },
+    
+    getCurrency : function()
+    {   
+        var v = this.currencyEl().getValue();
+        
+        return v;
+    },
+    
+    restrictHeight : function()
+    {
+        this.list.alignTo(this.currencyEl(), this.listAlign);
+        this.list.alignTo(this.currencyEl(), this.listAlign);
+    },
+    
+    onViewClick : function(view, doFocus, el, e)
+    {
+        var index = this.view.getSelectedIndexes()[0];
+        
+        var r = this.store.getAt(index);
+        
+        if(r){
+            this.onSelect(r, index);
+        }
+    },
+    
+    onSelect : function(record, index){
+        
+        if(this.fireEvent('beforeselect', this, record, index) !== false){
+        
+            this.setFromCurrencyData(index > -1 ? record.data : false);
+            
+            this.collapse();
+            
+            this.fireEvent('select', this, record, index);
+        }
+    },
+    
+    setFromCurrencyData : function(o)
+    {
+        var currency = '';
+        
+        this.lastCurrency = o;
+        
+        if (this.currencyField) {
+            currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
+        } else {
+            Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
+        }
+        
+        this.lastSelectionText = currency;
+        
+        //setting default currency
+        if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
+            this.setCurrency(this.defaultCurrency);
+            return;
+        }
+        
+        this.setCurrency(currency);
+    },
+    
+    setFromData : function(o)
+    {
+        var c = {};
+        
+        c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
+        
+        this.setFromCurrencyData(c);
+        
+        var value = '';
+        
+        if (this.name) {
+            value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
+        } else {
+            Roo.log('no value set for '+ (this.name ? this.name : this.id));
+        }
+        
+        this.setValue(value);
+        
+    },
+    
+    setCurrency : function(v)
+    {   
+        this.currencyValue = v;
+        
+        if(this.rendered){
+            this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
+            this.validate();
+        }
+    },
+    
+    setValue : function(v)
+    {
+        v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
+        
+        this.value = v;
+        
+        if(this.rendered){
+            
+            this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
+            
+            this.inputEl().dom.value = (v == '') ? '' :
+                Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
+            
+            if(!this.allowZero && v === '0') {
+                this.hiddenEl().dom.value = '';
+                this.inputEl().dom.value = '';
+            }
+            
+            this.validate();
+        }
+    },
+    
+    getRawValue : function()
+    {
+        var v = this.inputEl().getValue();
+        
+        return v;
+    },
+    
+    getValue : function()
+    {
+        return this.fixPrecision(this.parseValue(this.getRawValue()));
+    },
+    
+    parseValue : function(value)
+    {
+        if(this.thousandsDelimiter) {
+            value += "";
+            r = new RegExp(",", "g");
+            value = value.replace(r, "");
+        }
+        
+        value = parseFloat(String(value).replace(this.decimalSeparator, "."));
+        return isNaN(value) ? '' : value;
+        
+    },
+    
+    fixPrecision : function(value)
+    {
+        if(this.thousandsDelimiter) {
+            value += "";
+            r = new RegExp(",", "g");
+            value = value.replace(r, "");
+        }
+        
+        var nan = isNaN(value);
+        
+        if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
+            return nan ? '' : value;
+        }
+        return parseFloat(value).toFixed(this.decimalPrecision);
+    },
+    
+    decimalPrecisionFcn : function(v)
+    {
+        return Math.floor(v);
+    },
+    
+    validateValue : function(value)
+    {
+        if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
+            return false;
+        }
+        
+        var num = this.parseValue(value);
+        
+        if(isNaN(num)){
+            this.markInvalid(String.format(this.nanText, value));
+            return false;
+        }
+        
+        if(num < this.minValue){
+            this.markInvalid(String.format(this.minText, this.minValue));
+            return false;
+        }
+        
+        if(num > this.maxValue){
+            this.markInvalid(String.format(this.maxText, this.maxValue));
+            return false;
+        }
+        
+        return true;
+    },
+    
+    validate : function()
+    {
+        if(this.disabled || this.allowBlank){
+            this.markValid();
+            return true;
+        }
+        
+        var currency = this.getCurrency();
+        
+        if(this.validateValue(this.getRawValue()) && currency.length){
+            this.markValid();
+            return true;
+        }
+        
+        this.markInvalid();
+        return false;
+    },
+    
+    getName: function()
+    {
+        return this.name;
+    },
+    
+    beforeBlur : function()
+    {
+        if(!this.castInt){
+            return;
+        }
+        
+        var v = this.parseValue(this.getRawValue());
+        
+        if(v || v == 0){
+            this.setValue(v);
+        }
+    },
+    
+    onBlur : function()
+    {
+        this.beforeBlur();
+        
+        if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
+            //this.el.removeClass(this.focusClass);
+        }
+        
+        this.hasFocus = false;
+        
+        if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
+            this.validate();
+        }
+        
+        var v = this.getValue();
+        
+        if(String(v) !== String(this.startValue)){
+            this.fireEvent('change', this, v, this.startValue);
+        }
+        
+        this.fireEvent("blur", this);
+    },
+    
+    inputEl : function()
+    {
+        return this.el.select('.roo-money-amount-input', true).first();
+    },
+    
+    currencyEl : function()
+    {
+        return this.el.select('.roo-money-currency-input', true).first();
+    },
+    
+    hiddenEl : function()
+    {
+        return this.el.select('input.hidden-number-input',true).first();
+    }
+    
+});
\ No newline at end of file
diff --git a/Roo/bootstrap/form/MonthField.js b/Roo/bootstrap/form/MonthField.js
new file mode 100644 (file)
index 0000000..9348c26
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * - LGPL
+ *
+ * MonthField
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.MonthField
+ * @extends Roo.bootstrap.Input
+ * Bootstrap MonthField class
+ * 
+ * @cfg {String} language default en
+ * 
+ * @constructor
+ * Create a new MonthField
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.MonthField = function(config){
+    Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        /**
+         * @event show
+         * Fires when this field show.
+         * @param {Roo.bootstrap.MonthField} this
+         * @param {Mixed} date The date value
+         */
+        show : true,
+        /**
+         * @event show
+         * Fires when this field hide.
+         * @param {Roo.bootstrap.MonthField} this
+         * @param {Mixed} date The date value
+         */
+        hide : true,
+        /**
+         * @event select
+         * Fires when select a date.
+         * @param {Roo.bootstrap.MonthField} this
+         * @param {String} oldvalue The old value
+         * @param {String} newvalue The new value
+         */
+        select : true
+    });
+};
+
+Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
+    
+    onRender: function(ct, position)
+    {
+        
+        Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
+        
+        this.language = this.language || 'en';
+        this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
+        this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
+        
+        this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
+        this.isInline = false;
+        this.isInput = true;
+        this.component = this.el.select('.add-on', true).first() || false;
+        this.component = (this.component && this.component.length === 0) ? false : this.component;
+        this.hasInput = this.component && this.inputEL().length;
+        
+        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
+        
+        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.picker().on('mousedown', this.onMousedown, this);
+        this.picker().on('click', this.onClick, this);
+        
+        this.picker().addClass('datepicker-dropdown');
+        
+        Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
+            v.setStyle('width', '189px');
+        });
+        
+        this.fillMonths();
+        
+        this.update();
+        
+        if(this.isInline) {
+            this.show();
+        }
+        
+    },
+    
+    setValue: function(v, suppressEvent)
+    {   
+        var o = this.getValue();
+        
+        Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
+        
+        this.update();
+
+        if(suppressEvent !== true){
+            this.fireEvent('select', this, o, v);
+        }
+        
+    },
+    
+    getValue: function()
+    {
+        return this.value;
+    },
+    
+    onClick: function(e) 
+    {
+        e.stopPropagation();
+        e.preventDefault();
+        
+        var target = e.getTarget();
+        
+        if(target.nodeName.toLowerCase() === 'i'){
+            target = Roo.get(target).dom.parentNode;
+        }
+        
+        var nodeName = target.nodeName;
+        var className = target.className;
+        var html = target.innerHTML;
+        
+        if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
+            return;
+        }
+        
+        this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
+        
+        this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+        
+        this.hide();
+                        
+    },
+    
+    picker : function()
+    {
+        return this.pickerEl;
+    },
+    
+    fillMonths: function()
+    {    
+        var i = 0;
+        var months = this.picker().select('>.datepicker-months td', true).first();
+        
+        months.dom.innerHTML = '';
+        
+        while (i < 12) {
+            var month = {
+                tag: 'span',
+                cls: 'month',
+                html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
+            };
+            
+            months.createChild(month);
+        }
+        
+    },
+    
+    update: function()
+    {
+        var _this = this;
+        
+        if(typeof(this.vIndex) == 'undefined' && this.value.length){
+            this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
+        }
+        
+        Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
+            e.removeClass('active');
+            
+            if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
+                e.addClass('active');
+            }
+        })
+    },
+    
+    place: function()
+    {
+        if(this.isInline) {
+            return;
+        }
+        
+        this.picker().removeClass(['bottom', 'top']);
+        
+        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
+            /*
+             * place to the top of element!
+             *
+             */
+            
+            this.picker().addClass('top');
+            this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+            
+            return;
+        }
+        
+        this.picker().addClass('bottom');
+        
+        this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
+    },
+    
+    onFocus : function()
+    {
+        Roo.bootstrap.MonthField.superclass.onFocus.call(this);
+        this.show();
+    },
+    
+    onBlur : function()
+    {
+        Roo.bootstrap.MonthField.superclass.onBlur.call(this);
+        
+        var d = this.inputEl().getValue();
+        
+        this.setValue(d);
+                
+        this.hide();
+    },
+    
+    show : function()
+    {
+        this.picker().show();
+        this.picker().select('>.datepicker-months', true).first().show();
+        this.update();
+        this.place();
+        
+        this.fireEvent('show', this, this.date);
+    },
+    
+    hide : function()
+    {
+        if(this.isInline) {
+            return;
+        }
+        this.picker().hide();
+        this.fireEvent('hide', this, this.date);
+        
+    },
+    
+    onMousedown: function(e)
+    {
+        e.stopPropagation();
+        e.preventDefault();
+    },
+    
+    keyup: function(e)
+    {
+        Roo.bootstrap.MonthField.superclass.keyup.call(this);
+        this.update();
+    },
+
+    fireKey: function(e)
+    {
+        if (!this.picker().isVisible()){
+            if (e.keyCode == 27)   {// allow escape to hide and re-show picker
+                this.show();
+            }
+            return;
+        }
+        
+        var dir;
+        
+        switch(e.keyCode){
+            case 27: // escape
+                this.hide();
+                e.preventDefault();
+                break;
+            case 37: // left
+            case 39: // right
+                dir = e.keyCode == 37 ? -1 : 1;
+                
+                this.vIndex = this.vIndex + dir;
+                
+                if(this.vIndex < 0){
+                    this.vIndex = 0;
+                }
+                
+                if(this.vIndex > 11){
+                    this.vIndex = 11;
+                }
+                
+                if(isNaN(this.vIndex)){
+                    this.vIndex = 0;
+                }
+                
+                this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+                
+                break;
+            case 38: // up
+            case 40: // down
+                
+                dir = e.keyCode == 38 ? -1 : 1;
+                
+                this.vIndex = this.vIndex + dir * 4;
+                
+                if(this.vIndex < 0){
+                    this.vIndex = 0;
+                }
+                
+                if(this.vIndex > 11){
+                    this.vIndex = 11;
+                }
+                
+                if(isNaN(this.vIndex)){
+                    this.vIndex = 0;
+                }
+                
+                this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+                break;
+                
+            case 13: // enter
+                
+                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+                    this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+                }
+                
+                this.hide();
+                e.preventDefault();
+                break;
+            case 9: // tab
+                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+                    this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+                }
+                this.hide();
+                break;
+            case 16: // shift
+            case 17: // ctrl
+            case 18: // alt
+                break;
+            default :
+                this.hide();
+                
+        }
+    },
+    
+    remove: function() 
+    {
+        this.picker().remove();
+    }
+   
+});
+
+Roo.apply(Roo.bootstrap.MonthField,  {
+    
+    content : {
+        tag: 'tbody',
+        cn: [
+        {
+            tag: 'tr',
+            cn: [
+            {
+                tag: 'td',
+                colspan: '7'
+            }
+            ]
+        }
+        ]
+    },
+    
+    dates:{
+        en: {
+            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+        }
+    }
+});
+
+Roo.apply(Roo.bootstrap.MonthField,  {
+  
+    template : {
+        tag: 'div',
+        cls: 'datepicker dropdown-menu roo-dynamic',
+        cn: [
+            {
+                tag: 'div',
+                cls: 'datepicker-months',
+                cn: [
+                {
+                    tag: 'table',
+                    cls: 'table-condensed',
+                    cn:[
+                        Roo.bootstrap.DateField.content
+                    ]
+                }
+                ]
+            }
+        ]
+    }
+});
+
+
\ No newline at end of file
diff --git a/Roo/bootstrap/form/NumberField.js b/Roo/bootstrap/form/NumberField.js
new file mode 100644 (file)
index 0000000..e82d69f
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * - LGPL
+ *
+ * Number field 
+ */
+
+/**
+ * @class Roo.bootstrap.NumberField
+ * @extends Roo.bootstrap.Input
+ * Bootstrap NumberField class
+ * 
+ * 
+ * 
+ * 
+ * @constructor
+ * Create a new NumberField
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.NumberField = function(config){
+    Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
+    
+    /**
+     * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
+     */
+    allowDecimals : true,
+    /**
+     * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
+     */
+    decimalSeparator : ".",
+    /**
+     * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
+     */
+    decimalPrecision : 2,
+    /**
+     * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
+     */
+    allowNegative : true,
+    
+    /**
+     * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
+     */
+    allowZero: true,
+    /**
+     * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
+     */
+    minValue : Number.NEGATIVE_INFINITY,
+    /**
+     * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
+     */
+    maxValue : Number.MAX_VALUE,
+    /**
+     * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
+     */
+    minText : "The minimum value for this field is {0}",
+    /**
+     * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
+     */
+    maxText : "The maximum value for this field is {0}",
+    /**
+     * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
+     * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
+     */
+    nanText : "{0} is not a valid number",
+    /**
+     * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
+     */
+    thousandsDelimiter : false,
+    /**
+     * @cfg {String} valueAlign alignment of value
+     */
+    valueAlign : "left",
+
+    getAutoCreate : function()
+    {
+        var hiddenInput = {
+            tag: 'input',
+            type: 'hidden',
+            id: Roo.id(),
+            cls: 'hidden-number-input'
+        };
+        
+        if (this.name) {
+            hiddenInput.name = this.name;
+        }
+        
+        this.name = '';
+        
+        var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
+        
+        this.name = hiddenInput.name;
+        
+        if(cfg.cn.length > 0) {
+            cfg.cn.push(hiddenInput);
+        }
+        
+        return cfg;
+    },
+
+    // private
+    initEvents : function()
+    {   
+        Roo.bootstrap.NumberField.superclass.initEvents.call(this);
+        
+        var allowed = "0123456789";
+        
+        if(this.allowDecimals){
+            allowed += this.decimalSeparator;
+        }
+        
+        if(this.allowNegative){
+            allowed += "-";
+        }
+        
+        if(this.thousandsDelimiter) {
+            allowed += ",";
+        }
+        
+        this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
+        
+        var keyPress = function(e){
+            
+            var k = e.getKey();
+            
+            var c = e.getCharCode();
+            
+            if(
+                    (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
+                    allowed.indexOf(String.fromCharCode(c)) === -1
+            ){
+                e.stopEvent();
+                return;
+            }
+            
+            if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
+                return;
+            }
+            
+            if(allowed.indexOf(String.fromCharCode(c)) === -1){
+                e.stopEvent();
+            }
+        };
+        
+        this.el.on("keypress", keyPress, this);
+    },
+    
+    validateValue : function(value)
+    {
+        
+        if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
+            return false;
+        }
+        
+        var num = this.parseValue(value);
+        
+        if(isNaN(num)){
+            this.markInvalid(String.format(this.nanText, value));
+            return false;
+        }
+        
+        if(num < this.minValue){
+            this.markInvalid(String.format(this.minText, this.minValue));
+            return false;
+        }
+        
+        if(num > this.maxValue){
+            this.markInvalid(String.format(this.maxText, this.maxValue));
+            return false;
+        }
+        
+        return true;
+    },
+
+    getValue : function()
+    {
+        var v = this.hiddenEl().getValue();
+        
+        return this.fixPrecision(this.parseValue(v));
+    },
+
+    parseValue : function(value)
+    {
+        if(this.thousandsDelimiter) {
+            value += "";
+            r = new RegExp(",", "g");
+            value = value.replace(r, "");
+        }
+        
+        value = parseFloat(String(value).replace(this.decimalSeparator, "."));
+        return isNaN(value) ? '' : value;
+    },
+
+    fixPrecision : function(value)
+    {
+        if(this.thousandsDelimiter) {
+            value += "";
+            r = new RegExp(",", "g");
+            value = value.replace(r, "");
+        }
+        
+        var nan = isNaN(value);
+        
+        if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
+            return nan ? '' : value;
+        }
+        return parseFloat(value).toFixed(this.decimalPrecision);
+    },
+
+    setValue : function(v)
+    {
+        v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
+        
+        this.value = v;
+        
+        if(this.rendered){
+            
+            this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
+            
+            this.inputEl().dom.value = (v == '') ? '' :
+                Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
+            
+            if(!this.allowZero && v === '0') {
+                this.hiddenEl().dom.value = '';
+                this.inputEl().dom.value = '';
+            }
+            
+            this.validate();
+        }
+    },
+
+    decimalPrecisionFcn : function(v)
+    {
+        return Math.floor(v);
+    },
+
+    beforeBlur : function()
+    {
+        var v = this.parseValue(this.getRawValue());
+        
+        if(v || v === 0 || v === ''){
+            this.setValue(v);
+        }
+    },
+    
+    hiddenEl : function()
+    {
+        return this.el.select('input.hidden-number-input',true).first();
+    }
+    
+});
+
diff --git a/Roo/bootstrap/form/PhoneInput.js b/Roo/bootstrap/form/PhoneInput.js
new file mode 100644 (file)
index 0000000..d3d82f1
--- /dev/null
@@ -0,0 +1,562 @@
+/**
+*    This script refer to:
+*    Title: International Telephone Input
+*    Author: Jack O'Connor
+*    Code version:  v12.1.12
+*    Availability: https://github.com/jackocnr/intl-tel-input.git
+**/
+
+/**
+ * @class Roo.bootstrap.PhoneInput
+ * @extends Roo.bootstrap.TriggerField
+ * An input with International dial-code selection
+ * @cfg {String} defaultDialCode default '+852'
+ * @cfg {Array} preferedCountries default []
+  
+ * @constructor
+ * Create a new PhoneInput.
+ * @param {Object} config Configuration options
+ */
+
+Roo.bootstrap.PhoneInput = function(config) {
+    Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
+        /**
+        * @cfg {Roo.data.Store} store [required] The data store to which this combo is bound (defaults to undefined)
+        */
+        listWidth: undefined,
+        
+        selectedClass: 'active',
+        
+        invalidClass : "has-warning",
+        
+        validClass: 'has-success',
+        
+        allowed: '0123456789',
+        
+        max_length: 15,
+        
+        /**
+         * @cfg {String} defaultDialCode The default dial code when initializing the input
+         */
+        defaultDialCode: '+852',
+        
+        /**
+         * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
+         */
+        preferedCountries: false,
+        
+        getAutoCreate : function()
+        {
+            var data = Roo.bootstrap.PhoneInputData();
+            var align = this.labelAlign || this.parentLabelAlign();
+            var id = Roo.id();
+            
+            this.allCountries = [];
+            this.dialCodeMapping = [];
+            
+            for (var i = 0; i < data.length; i++) {
+              var c = data[i];
+              this.allCountries[i] = {
+                name: c[0],
+                iso2: c[1],
+                dialCode: c[2],
+                priority: c[3] || 0,
+                areaCodes: c[4] || null
+              };
+              this.dialCodeMapping[c[2]] = {
+                  name: c[0],
+                  iso2: c[1],
+                  priority: c[3] || 0,
+                  areaCodes: c[4] || null
+              };
+            }
+            
+            var cfg = {
+                cls: 'form-group',
+                cn: []
+            };
+            
+            var input =  {
+                tag: 'input',
+                id : id,
+                // type: 'number', -- do not use number - we get the flaky up/down arrows.
+                maxlength: this.max_length,
+                cls : 'form-control tel-input',
+                autocomplete: 'new-password'
+            };
+            
+            var hiddenInput = {
+                tag: 'input',
+                type: 'hidden',
+                cls: 'hidden-tel-input'
+            };
+            
+            if (this.name) {
+                hiddenInput.name = this.name;
+            }
+            
+            if (this.disabled) {
+                input.disabled = true;
+            }
+            
+            var flag_container = {
+                tag: 'div',
+                cls: 'flag-box',
+                cn: [
+                    {
+                        tag: 'div',
+                        cls: 'flag'
+                    },
+                    {
+                        tag: 'div',
+                        cls: 'caret'
+                    }
+                ]
+            };
+            
+            var box = {
+                tag: 'div',
+                cls: this.hasFeedback ? 'has-feedback' : '',
+                cn: [
+                    hiddenInput,
+                    input,
+                    {
+                        tag: 'input',
+                        cls: 'dial-code-holder',
+                        disabled: true
+                    }
+                ]
+            };
+            
+            var container = {
+                cls: 'roo-select2-container input-group',
+                cn: [
+                    flag_container,
+                    box
+                ]
+            };
+            
+            if (this.fieldLabel.length) {
+                var indicator = {
+                    tag: 'i',
+                    tooltip: 'This field is required'
+                };
+                
+                var label = {
+                    tag: 'label',
+                    'for':  id,
+                    cls: 'control-label',
+                    cn: []
+                };
+                
+                var label_text = {
+                    tag: 'span',
+                    html: this.fieldLabel
+                };
+                
+                indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
+                label.cn = [
+                    indicator,
+                    label_text
+                ];
+                
+                if(this.indicatorpos == 'right') {
+                    indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
+                    label.cn = [
+                        label_text,
+                        indicator
+                    ];
+                }
+                
+                if(align == 'left') {
+                    container = {
+                        tag: 'div',
+                        cn: [
+                            container
+                        ]
+                    };
+                    
+                    if(this.labelWidth > 12){
+                        label.style = "width: " + this.labelWidth + 'px';
+                    }
+                    if(this.labelWidth < 13 && this.labelmd == 0){
+                        this.labelmd = this.labelWidth;
+                    }
+                    if(this.labellg > 0){
+                        label.cls += ' col-lg-' + this.labellg;
+                        input.cls += ' col-lg-' + (12 - this.labellg);
+                    }
+                    if(this.labelmd > 0){
+                        label.cls += ' col-md-' + this.labelmd;
+                        container.cls += ' col-md-' + (12 - this.labelmd);
+                    }
+                    if(this.labelsm > 0){
+                        label.cls += ' col-sm-' + this.labelsm;
+                        container.cls += ' col-sm-' + (12 - this.labelsm);
+                    }
+                    if(this.labelxs > 0){
+                        label.cls += ' col-xs-' + this.labelxs;
+                        container.cls += ' col-xs-' + (12 - this.labelxs);
+                    }
+                }
+            }
+            
+            cfg.cn = [
+                label,
+                container
+            ];
+            
+            var settings = this;
+            
+            ['xs','sm','md','lg'].map(function(size){
+                if (settings[size]) {
+                    cfg.cls += ' col-' + size + '-' + settings[size];
+                }
+            });
+            
+            this.store = new Roo.data.Store({
+                proxy : new Roo.data.MemoryProxy({}),
+                reader : new Roo.data.JsonReader({
+                    fields : [
+                        {
+                            'name' : 'name',
+                            'type' : 'string'
+                        },
+                        {
+                            'name' : 'iso2',
+                            'type' : 'string'
+                        },
+                        {
+                            'name' : 'dialCode',
+                            'type' : 'string'
+                        },
+                        {
+                            'name' : 'priority',
+                            'type' : 'string'
+                        },
+                        {
+                            'name' : 'areaCodes',
+                            'type' : 'string'
+                        }
+                    ]
+                })
+            });
+            
+            if(!this.preferedCountries) {
+                this.preferedCountries = [
+                    'hk',
+                    'gb',
+                    'us'
+                ];
+            }
+            
+            var p = this.preferedCountries.reverse();
+            
+            if(p) {
+                for (var i = 0; i < p.length; i++) {
+                    for (var j = 0; j < this.allCountries.length; j++) {
+                        if(this.allCountries[j].iso2 == p[i]) {
+                            var t = this.allCountries[j];
+                            this.allCountries.splice(j,1);
+                            this.allCountries.unshift(t);
+                        }
+                    } 
+                }
+            }
+            
+            this.store.proxy.data = {
+                success: true,
+                data: this.allCountries
+            };
+            
+            return cfg;
+        },
+        
+        initEvents : function()
+        {
+            this.createList();
+            Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
+            
+            this.indicator = this.indicatorEl();
+            this.flag = this.flagEl();
+            this.dialCodeHolder = this.dialCodeHolderEl();
+            
+            this.trigger = this.el.select('div.flag-box',true).first();
+            this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
+            
+            var _this = this;
+            
+            (function(){
+                var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
+                _this.list.setWidth(lw);
+            }).defer(100);
+            
+            this.list.on('mouseover', this.onViewOver, this);
+            this.list.on('mousemove', this.onViewMove, this);
+            this.inputEl().on("keyup", this.onKeyUp, this);
+            this.inputEl().on("keypress", this.onKeyPress, this);
+            
+            this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
+
+            this.view = new Roo.View(this.list, this.tpl, {
+                singleSelect:true, store: this.store, selectedClass: this.selectedClass
+            });
+            
+            this.view.on('click', this.onViewClick, this);
+            this.setValue(this.defaultDialCode);
+        },
+        
+        onTriggerClick : function(e)
+        {
+            Roo.log('trigger click');
+            if(this.disabled){
+                return;
+            }
+            
+            if(this.isExpanded()){
+                this.collapse();
+                this.hasFocus = false;
+            }else {
+                this.store.load({});
+                this.hasFocus = true;
+                this.expand();
+            }
+        },
+        
+        isExpanded : function()
+        {
+            return this.list.isVisible();
+        },
+        
+        collapse : function()
+        {
+            if(!this.isExpanded()){
+                return;
+            }
+            this.list.hide();
+            Roo.get(document).un('mousedown', this.collapseIf, this);
+            Roo.get(document).un('mousewheel', this.collapseIf, this);
+            this.fireEvent('collapse', this);
+            this.validate();
+        },
+        
+        expand : function()
+        {
+            Roo.log('expand');
+
+            if(this.isExpanded() || !this.hasFocus){
+                return;
+            }
+            
+            var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
+            this.list.setWidth(lw);
+            
+            this.list.show();
+            this.restrictHeight();
+            
+            Roo.get(document).on('mousedown', this.collapseIf, this);
+            Roo.get(document).on('mousewheel', this.collapseIf, this);
+            
+            this.fireEvent('expand', this);
+        },
+        
+        restrictHeight : function()
+        {
+            this.list.alignTo(this.inputEl(), this.listAlign);
+            this.list.alignTo(this.inputEl(), this.listAlign);
+        },
+        
+        onViewOver : function(e, t)
+        {
+            if(this.inKeyMode){
+                return;
+            }
+            var item = this.view.findItemFromChild(t);
+            
+            if(item){
+                var index = this.view.indexOf(item);
+                this.select(index, false);
+            }
+        },
+
+        // private
+        onViewClick : function(view, doFocus, el, e)
+        {
+            var index = this.view.getSelectedIndexes()[0];
+            
+            var r = this.store.getAt(index);
+            
+            if(r){
+                this.onSelect(r, index);
+            }
+            if(doFocus !== false && !this.blockFocus){
+                this.inputEl().focus();
+            }
+        },
+        
+        onViewMove : function(e, t)
+        {
+            this.inKeyMode = false;
+        },
+        
+        select : function(index, scrollIntoView)
+        {
+            this.selectedIndex = index;
+            this.view.select(index);
+            if(scrollIntoView !== false){
+                var el = this.view.getNode(index);
+                if(el){
+                    this.list.scrollChildIntoView(el, false);
+                }
+            }
+        },
+        
+        createList : function()
+        {
+            this.list = Roo.get(document.body).createChild({
+                tag: 'ul',
+                cls: 'typeahead typeahead-long dropdown-menu tel-list',
+                style: 'display:none'
+            });
+            
+            this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        },
+        
+        collapseIf : function(e)
+        {
+            var in_combo  = e.within(this.el);
+            var in_list =  e.within(this.list);
+            var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
+            
+            if (in_combo || in_list || is_list) {
+                return;
+            }
+            this.collapse();
+        },
+        
+        onSelect : function(record, index)
+        {
+            if(this.fireEvent('beforeselect', this, record, index) !== false){
+                
+                this.setFlagClass(record.data.iso2);
+                this.setDialCode(record.data.dialCode);
+                this.hasFocus = false;
+                this.collapse();
+                this.fireEvent('select', this, record, index);
+            }
+        },
+        
+        flagEl : function()
+        {
+            var flag = this.el.select('div.flag',true).first();
+            if(!flag){
+                return false;
+            }
+            return flag;
+        },
+        
+        dialCodeHolderEl : function()
+        {
+            var d = this.el.select('input.dial-code-holder',true).first();
+            if(!d){
+                return false;
+            }
+            return d;
+        },
+        
+        setDialCode : function(v)
+        {
+            this.dialCodeHolder.dom.value = '+'+v;
+        },
+        
+        setFlagClass : function(n)
+        {
+            this.flag.dom.className = 'flag '+n;
+        },
+        
+        getValue : function()
+        {
+            var v = this.inputEl().getValue();
+            if(this.dialCodeHolder) {
+                v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
+            }
+            return v;
+        },
+        
+        setValue : function(v)
+        {
+            var d = this.getDialCode(v);
+            
+            //invalid dial code
+            if(v.length == 0 || !d || d.length == 0) {
+                if(this.rendered){
+                    this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
+                    this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
+                }
+                return;
+            }
+            
+            //valid dial code
+            this.setFlagClass(this.dialCodeMapping[d].iso2);
+            this.setDialCode(d);
+            this.inputEl().dom.value = v.replace('+'+d,'');
+            this.hiddenEl().dom.value = this.getValue();
+            
+            this.validate();
+        },
+        
+        getDialCode : function(v)
+        {
+            v = v ||  '';
+            
+            if (v.length == 0) {
+                return this.dialCodeHolder.dom.value;
+            }
+            
+            var dialCode = "";
+            if (v.charAt(0) != "+") {
+                return false;
+            }
+            var numericChars = "";
+            for (var i = 1; i < v.length; i++) {
+              var c = v.charAt(i);
+              if (!isNaN(c)) {
+                numericChars += c;
+                if (this.dialCodeMapping[numericChars]) {
+                  dialCode = v.substr(1, i);
+                }
+                if (numericChars.length == 4) {
+                  break;
+                }
+              }
+            }
+            return dialCode;
+        },
+        
+        reset : function()
+        {
+            this.setValue(this.defaultDialCode);
+            this.validate();
+        },
+        
+        hiddenEl : function()
+        {
+            return this.el.select('input.hidden-tel-input',true).first();
+        },
+        
+        // after setting val
+        onKeyUp : function(e){
+            this.setValue(this.getValue());
+        },
+        
+        onKeyPress : function(e){
+            if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
+                e.stopEvent();
+            }
+        }
+        
+});
\ No newline at end of file
diff --git a/Roo/bootstrap/form/PhoneInputData.js b/Roo/bootstrap/form/PhoneInputData.js
new file mode 100644 (file)
index 0000000..88039e0
--- /dev/null
@@ -0,0 +1,1260 @@
+/**
+*    This script refer to:
+*    Title: International Telephone Input
+*    Author: Jack O'Connor
+*    Code version:  v12.1.12
+*    Availability: https://github.com/jackocnr/intl-tel-input.git
+**/
+
+Roo.bootstrap.PhoneInputData = function() {
+    var d = [
+      [
+        "Afghanistan (‫افغانستان‬‎)",
+        "af",
+        "93"
+      ],
+      [
+        "Albania (Shqipëri)",
+        "al",
+        "355"
+      ],
+      [
+        "Algeria (‫الجزائر‬‎)",
+        "dz",
+        "213"
+      ],
+      [
+        "American Samoa",
+        "as",
+        "1684"
+      ],
+      [
+        "Andorra",
+        "ad",
+        "376"
+      ],
+      [
+        "Angola",
+        "ao",
+        "244"
+      ],
+      [
+        "Anguilla",
+        "ai",
+        "1264"
+      ],
+      [
+        "Antigua and Barbuda",
+        "ag",
+        "1268"
+      ],
+      [
+        "Argentina",
+        "ar",
+        "54"
+      ],
+      [
+        "Armenia (Հայաստան)",
+        "am",
+        "374"
+      ],
+      [
+        "Aruba",
+        "aw",
+        "297"
+      ],
+      [
+        "Australia",
+        "au",
+        "61",
+        0
+      ],
+      [
+        "Austria (Österreich)",
+        "at",
+        "43"
+      ],
+      [
+        "Azerbaijan (Azərbaycan)",
+        "az",
+        "994"
+      ],
+      [
+        "Bahamas",
+        "bs",
+        "1242"
+      ],
+      [
+        "Bahrain (‫البحرين‬‎)",
+        "bh",
+        "973"
+      ],
+      [
+        "Bangladesh (বাংলাদেশ)",
+        "bd",
+        "880"
+      ],
+      [
+        "Barbados",
+        "bb",
+        "1246"
+      ],
+      [
+        "Belarus (Беларусь)",
+        "by",
+        "375"
+      ],
+      [
+        "Belgium (België)",
+        "be",
+        "32"
+      ],
+      [
+        "Belize",
+        "bz",
+        "501"
+      ],
+      [
+        "Benin (Bénin)",
+        "bj",
+        "229"
+      ],
+      [
+        "Bermuda",
+        "bm",
+        "1441"
+      ],
+      [
+        "Bhutan (འབྲུག)",
+        "bt",
+        "975"
+      ],
+      [
+        "Bolivia",
+        "bo",
+        "591"
+      ],
+      [
+        "Bosnia and Herzegovina (Босна и Херцеговина)",
+        "ba",
+        "387"
+      ],
+      [
+        "Botswana",
+        "bw",
+        "267"
+      ],
+      [
+        "Brazil (Brasil)",
+        "br",
+        "55"
+      ],
+      [
+        "British Indian Ocean Territory",
+        "io",
+        "246"
+      ],
+      [
+        "British Virgin Islands",
+        "vg",
+        "1284"
+      ],
+      [
+        "Brunei",
+        "bn",
+        "673"
+      ],
+      [
+        "Bulgaria (България)",
+        "bg",
+        "359"
+      ],
+      [
+        "Burkina Faso",
+        "bf",
+        "226"
+      ],
+      [
+        "Burundi (Uburundi)",
+        "bi",
+        "257"
+      ],
+      [
+        "Cambodia (កម្ពុជា)",
+        "kh",
+        "855"
+      ],
+      [
+        "Cameroon (Cameroun)",
+        "cm",
+        "237"
+      ],
+      [
+        "Canada",
+        "ca",
+        "1",
+        1,
+        ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
+      ],
+      [
+        "Cape Verde (Kabu Verdi)",
+        "cv",
+        "238"
+      ],
+      [
+        "Caribbean Netherlands",
+        "bq",
+        "599",
+        1
+      ],
+      [
+        "Cayman Islands",
+        "ky",
+        "1345"
+      ],
+      [
+        "Central African Republic (République centrafricaine)",
+        "cf",
+        "236"
+      ],
+      [
+        "Chad (Tchad)",
+        "td",
+        "235"
+      ],
+      [
+        "Chile",
+        "cl",
+        "56"
+      ],
+      [
+        "China (中国)",
+        "cn",
+        "86"
+      ],
+      [
+        "Christmas Island",
+        "cx",
+        "61",
+        2
+      ],
+      [
+        "Cocos (Keeling) Islands",
+        "cc",
+        "61",
+        1
+      ],
+      [
+        "Colombia",
+        "co",
+        "57"
+      ],
+      [
+        "Comoros (‫جزر القمر‬‎)",
+        "km",
+        "269"
+      ],
+      [
+        "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
+        "cd",
+        "243"
+      ],
+      [
+        "Congo (Republic) (Congo-Brazzaville)",
+        "cg",
+        "242"
+      ],
+      [
+        "Cook Islands",
+        "ck",
+        "682"
+      ],
+      [
+        "Costa Rica",
+        "cr",
+        "506"
+      ],
+      [
+        "Côte d’Ivoire",
+        "ci",
+        "225"
+      ],
+      [
+        "Croatia (Hrvatska)",
+        "hr",
+        "385"
+      ],
+      [
+        "Cuba",
+        "cu",
+        "53"
+      ],
+      [
+        "Curaçao",
+        "cw",
+        "599",
+        0
+      ],
+      [
+        "Cyprus (Κύπρος)",
+        "cy",
+        "357"
+      ],
+      [
+        "Czech Republic (Česká republika)",
+        "cz",
+        "420"
+      ],
+      [
+        "Denmark (Danmark)",
+        "dk",
+        "45"
+      ],
+      [
+        "Djibouti",
+        "dj",
+        "253"
+      ],
+      [
+        "Dominica",
+        "dm",
+        "1767"
+      ],
+      [
+        "Dominican Republic (República Dominicana)",
+        "do",
+        "1",
+        2,
+        ["809", "829", "849"]
+      ],
+      [
+        "Ecuador",
+        "ec",
+        "593"
+      ],
+      [
+        "Egypt (‫مصر‬‎)",
+        "eg",
+        "20"
+      ],
+      [
+        "El Salvador",
+        "sv",
+        "503"
+      ],
+      [
+        "Equatorial Guinea (Guinea Ecuatorial)",
+        "gq",
+        "240"
+      ],
+      [
+        "Eritrea",
+        "er",
+        "291"
+      ],
+      [
+        "Estonia (Eesti)",
+        "ee",
+        "372"
+      ],
+      [
+        "Ethiopia",
+        "et",
+        "251"
+      ],
+      [
+        "Falkland Islands (Islas Malvinas)",
+        "fk",
+        "500"
+      ],
+      [
+        "Faroe Islands (Føroyar)",
+        "fo",
+        "298"
+      ],
+      [
+        "Fiji",
+        "fj",
+        "679"
+      ],
+      [
+        "Finland (Suomi)",
+        "fi",
+        "358",
+        0
+      ],
+      [
+        "France",
+        "fr",
+        "33"
+      ],
+      [
+        "French Guiana (Guyane française)",
+        "gf",
+        "594"
+      ],
+      [
+        "French Polynesia (Polynésie française)",
+        "pf",
+        "689"
+      ],
+      [
+        "Gabon",
+        "ga",
+        "241"
+      ],
+      [
+        "Gambia",
+        "gm",
+        "220"
+      ],
+      [
+        "Georgia (საქართველო)",
+        "ge",
+        "995"
+      ],
+      [
+        "Germany (Deutschland)",
+        "de",
+        "49"
+      ],
+      [
+        "Ghana (Gaana)",
+        "gh",
+        "233"
+      ],
+      [
+        "Gibraltar",
+        "gi",
+        "350"
+      ],
+      [
+        "Greece (Ελλάδα)",
+        "gr",
+        "30"
+      ],
+      [
+        "Greenland (Kalaallit Nunaat)",
+        "gl",
+        "299"
+      ],
+      [
+        "Grenada",
+        "gd",
+        "1473"
+      ],
+      [
+        "Guadeloupe",
+        "gp",
+        "590",
+        0
+      ],
+      [
+        "Guam",
+        "gu",
+        "1671"
+      ],
+      [
+        "Guatemala",
+        "gt",
+        "502"
+      ],
+      [
+        "Guernsey",
+        "gg",
+        "44",
+        1
+      ],
+      [
+        "Guinea (Guinée)",
+        "gn",
+        "224"
+      ],
+      [
+        "Guinea-Bissau (Guiné Bissau)",
+        "gw",
+        "245"
+      ],
+      [
+        "Guyana",
+        "gy",
+        "592"
+      ],
+      [
+        "Haiti",
+        "ht",
+        "509"
+      ],
+      [
+        "Honduras",
+        "hn",
+        "504"
+      ],
+      [
+        "Hong Kong (香港)",
+        "hk",
+        "852"
+      ],
+      [
+        "Hungary (Magyarország)",
+        "hu",
+        "36"
+      ],
+      [
+        "Iceland (Ísland)",
+        "is",
+        "354"
+      ],
+      [
+        "India (भारत)",
+        "in",
+        "91"
+      ],
+      [
+        "Indonesia",
+        "id",
+        "62"
+      ],
+      [
+        "Iran (‫ایران‬‎)",
+        "ir",
+        "98"
+      ],
+      [
+        "Iraq (‫العراق‬‎)",
+        "iq",
+        "964"
+      ],
+      [
+        "Ireland",
+        "ie",
+        "353"
+      ],
+      [
+        "Isle of Man",
+        "im",
+        "44",
+        2
+      ],
+      [
+        "Israel (‫ישראל‬‎)",
+        "il",
+        "972"
+      ],
+      [
+        "Italy (Italia)",
+        "it",
+        "39",
+        0
+      ],
+      [
+        "Jamaica",
+        "jm",
+        "1876"
+      ],
+      [
+        "Japan (日本)",
+        "jp",
+        "81"
+      ],
+      [
+        "Jersey",
+        "je",
+        "44",
+        3
+      ],
+      [
+        "Jordan (‫الأردن‬‎)",
+        "jo",
+        "962"
+      ],
+      [
+        "Kazakhstan (Казахстан)",
+        "kz",
+        "7",
+        1
+      ],
+      [
+        "Kenya",
+        "ke",
+        "254"
+      ],
+      [
+        "Kiribati",
+        "ki",
+        "686"
+      ],
+      [
+        "Kosovo",
+        "xk",
+        "383"
+      ],
+      [
+        "Kuwait (‫الكويت‬‎)",
+        "kw",
+        "965"
+      ],
+      [
+        "Kyrgyzstan (Кыргызстан)",
+        "kg",
+        "996"
+      ],
+      [
+        "Laos (ລາວ)",
+        "la",
+        "856"
+      ],
+      [
+        "Latvia (Latvija)",
+        "lv",
+        "371"
+      ],
+      [
+        "Lebanon (‫لبنان‬‎)",
+        "lb",
+        "961"
+      ],
+      [
+        "Lesotho",
+        "ls",
+        "266"
+      ],
+      [
+        "Liberia",
+        "lr",
+        "231"
+      ],
+      [
+        "Libya (‫ليبيا‬‎)",
+        "ly",
+        "218"
+      ],
+      [
+        "Liechtenstein",
+        "li",
+        "423"
+      ],
+      [
+        "Lithuania (Lietuva)",
+        "lt",
+        "370"
+      ],
+      [
+        "Luxembourg",
+        "lu",
+        "352"
+      ],
+      [
+        "Macau (澳門)",
+        "mo",
+        "853"
+      ],
+      [
+        "Macedonia (FYROM) (Македонија)",
+        "mk",
+        "389"
+      ],
+      [
+        "Madagascar (Madagasikara)",
+        "mg",
+        "261"
+      ],
+      [
+        "Malawi",
+        "mw",
+        "265"
+      ],
+      [
+        "Malaysia",
+        "my",
+        "60"
+      ],
+      [
+        "Maldives",
+        "mv",
+        "960"
+      ],
+      [
+        "Mali",
+        "ml",
+        "223"
+      ],
+      [
+        "Malta",
+        "mt",
+        "356"
+      ],
+      [
+        "Marshall Islands",
+        "mh",
+        "692"
+      ],
+      [
+        "Martinique",
+        "mq",
+        "596"
+      ],
+      [
+        "Mauritania (‫موريتانيا‬‎)",
+        "mr",
+        "222"
+      ],
+      [
+        "Mauritius (Moris)",
+        "mu",
+        "230"
+      ],
+      [
+        "Mayotte",
+        "yt",
+        "262",
+        1
+      ],
+      [
+        "Mexico (México)",
+        "mx",
+        "52"
+      ],
+      [
+        "Micronesia",
+        "fm",
+        "691"
+      ],
+      [
+        "Moldova (Republica Moldova)",
+        "md",
+        "373"
+      ],
+      [
+        "Monaco",
+        "mc",
+        "377"
+      ],
+      [
+        "Mongolia (Монгол)",
+        "mn",
+        "976"
+      ],
+      [
+        "Montenegro (Crna Gora)",
+        "me",
+        "382"
+      ],
+      [
+        "Montserrat",
+        "ms",
+        "1664"
+      ],
+      [
+        "Morocco (‫المغرب‬‎)",
+        "ma",
+        "212",
+        0
+      ],
+      [
+        "Mozambique (Moçambique)",
+        "mz",
+        "258"
+      ],
+      [
+        "Myanmar (Burma) (မြန်မာ)",
+        "mm",
+        "95"
+      ],
+      [
+        "Namibia (Namibië)",
+        "na",
+        "264"
+      ],
+      [
+        "Nauru",
+        "nr",
+        "674"
+      ],
+      [
+        "Nepal (नेपाल)",
+        "np",
+        "977"
+      ],
+      [
+        "Netherlands (Nederland)",
+        "nl",
+        "31"
+      ],
+      [
+        "New Caledonia (Nouvelle-Calédonie)",
+        "nc",
+        "687"
+      ],
+      [
+        "New Zealand",
+        "nz",
+        "64"
+      ],
+      [
+        "Nicaragua",
+        "ni",
+        "505"
+      ],
+      [
+        "Niger (Nijar)",
+        "ne",
+        "227"
+      ],
+      [
+        "Nigeria",
+        "ng",
+        "234"
+      ],
+      [
+        "Niue",
+        "nu",
+        "683"
+      ],
+      [
+        "Norfolk Island",
+        "nf",
+        "672"
+      ],
+      [
+        "North Korea (조선 민주주의 인민 공화국)",
+        "kp",
+        "850"
+      ],
+      [
+        "Northern Mariana Islands",
+        "mp",
+        "1670"
+      ],
+      [
+        "Norway (Norge)",
+        "no",
+        "47",
+        0
+      ],
+      [
+        "Oman (‫عُمان‬‎)",
+        "om",
+        "968"
+      ],
+      [
+        "Pakistan (‫پاکستان‬‎)",
+        "pk",
+        "92"
+      ],
+      [
+        "Palau",
+        "pw",
+        "680"
+      ],
+      [
+        "Palestine (‫فلسطين‬‎)",
+        "ps",
+        "970"
+      ],
+      [
+        "Panama (Panamá)",
+        "pa",
+        "507"
+      ],
+      [
+        "Papua New Guinea",
+        "pg",
+        "675"
+      ],
+      [
+        "Paraguay",
+        "py",
+        "595"
+      ],
+      [
+        "Peru (Perú)",
+        "pe",
+        "51"
+      ],
+      [
+        "Philippines",
+        "ph",
+        "63"
+      ],
+      [
+        "Poland (Polska)",
+        "pl",
+        "48"
+      ],
+      [
+        "Portugal",
+        "pt",
+        "351"
+      ],
+      [
+        "Puerto Rico",
+        "pr",
+        "1",
+        3,
+        ["787", "939"]
+      ],
+      [
+        "Qatar (‫قطر‬‎)",
+        "qa",
+        "974"
+      ],
+      [
+        "Réunion (La Réunion)",
+        "re",
+        "262",
+        0
+      ],
+      [
+        "Romania (România)",
+        "ro",
+        "40"
+      ],
+      [
+        "Russia (Россия)",
+        "ru",
+        "7",
+        0
+      ],
+      [
+        "Rwanda",
+        "rw",
+        "250"
+      ],
+      [
+        "Saint Barthélemy",
+        "bl",
+        "590",
+        1
+      ],
+      [
+        "Saint Helena",
+        "sh",
+        "290"
+      ],
+      [
+        "Saint Kitts and Nevis",
+        "kn",
+        "1869"
+      ],
+      [
+        "Saint Lucia",
+        "lc",
+        "1758"
+      ],
+      [
+        "Saint Martin (Saint-Martin (partie française))",
+        "mf",
+        "590",
+        2
+      ],
+      [
+        "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
+        "pm",
+        "508"
+      ],
+      [
+        "Saint Vincent and the Grenadines",
+        "vc",
+        "1784"
+      ],
+      [
+        "Samoa",
+        "ws",
+        "685"
+      ],
+      [
+        "San Marino",
+        "sm",
+        "378"
+      ],
+      [
+        "São Tomé and Príncipe (São Tomé e Príncipe)",
+        "st",
+        "239"
+      ],
+      [
+        "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
+        "sa",
+        "966"
+      ],
+      [
+        "Senegal (Sénégal)",
+        "sn",
+        "221"
+      ],
+      [
+        "Serbia (Србија)",
+        "rs",
+        "381"
+      ],
+      [
+        "Seychelles",
+        "sc",
+        "248"
+      ],
+      [
+        "Sierra Leone",
+        "sl",
+        "232"
+      ],
+      [
+        "Singapore",
+        "sg",
+        "65"
+      ],
+      [
+        "Sint Maarten",
+        "sx",
+        "1721"
+      ],
+      [
+        "Slovakia (Slovensko)",
+        "sk",
+        "421"
+      ],
+      [
+        "Slovenia (Slovenija)",
+        "si",
+        "386"
+      ],
+      [
+        "Solomon Islands",
+        "sb",
+        "677"
+      ],
+      [
+        "Somalia (Soomaaliya)",
+        "so",
+        "252"
+      ],
+      [
+        "South Africa",
+        "za",
+        "27"
+      ],
+      [
+        "South Korea (대한민국)",
+        "kr",
+        "82"
+      ],
+      [
+        "South Sudan (‫جنوب السودان‬‎)",
+        "ss",
+        "211"
+      ],
+      [
+        "Spain (España)",
+        "es",
+        "34"
+      ],
+      [
+        "Sri Lanka (ශ්‍රී ලංකාව)",
+        "lk",
+        "94"
+      ],
+      [
+        "Sudan (‫السودان‬‎)",
+        "sd",
+        "249"
+      ],
+      [
+        "Suriname",
+        "sr",
+        "597"
+      ],
+      [
+        "Svalbard and Jan Mayen",
+        "sj",
+        "47",
+        1
+      ],
+      [
+        "Swaziland",
+        "sz",
+        "268"
+      ],
+      [
+        "Sweden (Sverige)",
+        "se",
+        "46"
+      ],
+      [
+        "Switzerland (Schweiz)",
+        "ch",
+        "41"
+      ],
+      [
+        "Syria (‫سوريا‬‎)",
+        "sy",
+        "963"
+      ],
+      [
+        "Taiwan (台灣)",
+        "tw",
+        "886"
+      ],
+      [
+        "Tajikistan",
+        "tj",
+        "992"
+      ],
+      [
+        "Tanzania",
+        "tz",
+        "255"
+      ],
+      [
+        "Thailand (ไทย)",
+        "th",
+        "66"
+      ],
+      [
+        "Timor-Leste",
+        "tl",
+        "670"
+      ],
+      [
+        "Togo",
+        "tg",
+        "228"
+      ],
+      [
+        "Tokelau",
+        "tk",
+        "690"
+      ],
+      [
+        "Tonga",
+        "to",
+        "676"
+      ],
+      [
+        "Trinidad and Tobago",
+        "tt",
+        "1868"
+      ],
+      [
+        "Tunisia (‫تونس‬‎)",
+        "tn",
+        "216"
+      ],
+      [
+        "Turkey (Türkiye)",
+        "tr",
+        "90"
+      ],
+      [
+        "Turkmenistan",
+        "tm",
+        "993"
+      ],
+      [
+        "Turks and Caicos Islands",
+        "tc",
+        "1649"
+      ],
+      [
+        "Tuvalu",
+        "tv",
+        "688"
+      ],
+      [
+        "U.S. Virgin Islands",
+        "vi",
+        "1340"
+      ],
+      [
+        "Uganda",
+        "ug",
+        "256"
+      ],
+      [
+        "Ukraine (Україна)",
+        "ua",
+        "380"
+      ],
+      [
+        "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
+        "ae",
+        "971"
+      ],
+      [
+        "United Kingdom",
+        "gb",
+        "44",
+        0
+      ],
+      [
+        "United States",
+        "us",
+        "1",
+        0
+      ],
+      [
+        "Uruguay",
+        "uy",
+        "598"
+      ],
+      [
+        "Uzbekistan (Oʻzbekiston)",
+        "uz",
+        "998"
+      ],
+      [
+        "Vanuatu",
+        "vu",
+        "678"
+      ],
+      [
+        "Vatican City (Città del Vaticano)",
+        "va",
+        "39",
+        1
+      ],
+      [
+        "Venezuela",
+        "ve",
+        "58"
+      ],
+      [
+        "Vietnam (Việt Nam)",
+        "vn",
+        "84"
+      ],
+      [
+        "Wallis and Futuna (Wallis-et-Futuna)",
+        "wf",
+        "681"
+      ],
+      [
+        "Western Sahara (‫الصحراء الغربية‬‎)",
+        "eh",
+        "212",
+        1
+      ],
+      [
+        "Yemen (‫اليمن‬‎)",
+        "ye",
+        "967"
+      ],
+      [
+        "Zambia",
+        "zm",
+        "260"
+      ],
+      [
+        "Zimbabwe",
+        "zw",
+        "263"
+      ],
+      [
+        "Åland Islands",
+        "ax",
+        "358",
+        1
+      ]
+  ];
+  
+  return d;
+}
\ No newline at end of file