MOVED Roo/bootstrap/PhoneInput.js to Roo/bootstrap/form/PhoneInput.js
[roojs1] / Roo / bootstrap / form / PhoneInput.js
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