Hi,

Please find updated patch.

-- 
*Harshal Dhumal*
*Sr. Software Engineer*

EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

On Tue, May 30, 2017 at 12:30 PM, Harshal Dhumal <
harshal.dhu...@enterprisedb.com> wrote:

> Hi,
>
> Please ignore this patch as I forgot to include few changes. I'll send
> updated one.
>
> --
> *Harshal Dhumal*
> *Sr. Software Engineer*
>
> EnterpriseDB India: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Mon, May 29, 2017 at 3:18 PM, Harshal Dhumal <
> harshal.dhu...@enterprisedb.com> wrote:
>
>> Hi,
>>
>> Here is updated patch for RM2421.
>>
>> Now I have moved all Numeric control level validations to datamodel. As
>> existing implementation was causing
>> issues with error messages in create/edit dialog when schema contains two
>> or more Numeric controls.
>>
>> This is generic issue and not related to resource group. Also I have
>> updated all other nodes which uses Numeric controls
>>
>>
>>
>> --
>> *Harshal Dhumal*
>> *Sr. Software Engineer*
>>
>> EnterpriseDB India: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Fri, May 19, 2017 at 12:22 PM, Harshal Dhumal <
>> harshal.dhu...@enterprisedb.com> wrote:
>>
>>> Hi,
>>>
>>> On Thu, May 18, 2017 at 7:57 PM, Joao Pedro De Almeida Pereira <
>>> jdealmeidapere...@pivotal.io> wrote:
>>>
>>>> Hello Harshal,
>>>>
>>>> We review the patch and have some questions:
>>>> 1) Is there any particular reason to initialize variables and functions
>>>> in the same place? We believe that it would be more readable there were no
>>>> chaining of variable creation, specially if those variables are functions.
>>>> Check line:
>>>>
>>> That function is only going to be used in checkNumeric function (in case
>>> of Number control) and checkInt function (in case of Integer control) so
>>> declared them locally.
>>> Anyway I'm going to refactor both the controls as Number and Integer
>>> shares some common properties.
>>>
>>> +++ b/web/pgadmin/static/js/backform.pgadmin.js
>>>> @@ -1528,7 +1528,18 @@
>>>>            max_value = field.max,
>>>>            isValid = true,
>>>>            intPattern = new RegExp("^-?[0-9]*$"),
>>>> -          isMatched = intPattern.test(value);
>>>> +          isMatched = intPattern.test(value),
>>>> +          trigger_invalid_event = function(msg) {
>>>>
>>>> ​
>>>> 2) The functions added in both places look very similar, can they be
>>>> merged and extracted? We are talking about the trigger_invalid_event
>>>>  function.
>>>>
>>> Yes they can be merged. As of now both NumericControl and IntegerControl
>>> are derived from InputControl. Ideally
>>> only NumericControl should be derived from InputControl and
>>> IntegerControl should be derive from NumericControl.
>>>
>>>
>>>
>>>> 3) The following change is very similar to the trigger_invalid_event,
>>>> was there a reason not to use it?
>>>>
>>> Below code triggers "model valid" event; opposite to "model invalid"
>>> event (trigger_invalid_event)
>>>
>>>> +++ b/web/pgadmin/static/js/backform.pgadmin.js
>>>> @@ -1573,25 +1584,23 @@
>>>>          this.model.errorModel.unset(name);
>>>>          this.model.set(name, value);
>>>>          this.listenTo(this.model, "change:" + name, this.render);
>>>> -        if (this.model.collection || this.model.handler) {
>>>> -          (this.model.collection || this.model.handler).trigger(
>>>> -             'pgadmin-session:model:valid', this.model, 
>>>> (this.model.collection || this.model.handler)
>>>> -            );
>>>> +        // Check if other fields of same model are valid before
>>>> +        // triggering 'session:valid' event
>>>> +        if(_.size(this.model.errorModel.attributes) == 0) {
>>>> +          if (this.model.collection || this.model.handler) {
>>>> +            (this.model.collection || this.model.handler).trigger(
>>>> +               'pgadmin-session:model:valid', this.model, 
>>>> (this.model.collection || this.model.handler)
>>>> +              );
>>>> +          } else {
>>>> +            (this.model).trigger(
>>>> +               'pgadmin-session:valid', this.model.sessChanged(), 
>>>> this.model
>>>> +              );
>>>> +          }
>>>>
>>>> ​
>>>> 4) We also noticed that the following change sets look very similiar.
>>>> Is there any reason to have this code duplicated? If not this could be a
>>>> good time to refactor it.
>>>>
>>> As said earlier in response of point 2 code duplication is because the
>>> way controls are derived.
>>>
>>>
>>>> +++ b/web/pgadmin/static/js/backform.pgadmin.js
>>>> @@ -1528,7 +1528,18 @@
>>>>
>>>> @@ -1573,25 +1584,23 @@
>>>>
>>>> @@ -1631,7 +1640,18 @@
>>>>
>>>> @@ -1676,25 +1696,23 @@
>>>>
>>>> ​
>>>>
>>>> Thanks
>>>> Joao & Shruti
>>>>
>>>> On Thu, May 18, 2017 at 6:01 AM, Harshal Dhumal <
>>>> harshal.dhu...@enterprisedb.com> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please find attached patch for RM2421
>>>>>
>>>>> Issue fixed: 1. Integer/numeric Validation is not working properly.
>>>>> 2. Wrong CPU rate unit
>>>>> --
>>>>> *Harshal Dhumal*
>>>>> *Sr. Software Engineer*
>>>>>
>>>>> EnterpriseDB India: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>>
>>>>> --
>>>>> Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org)
>>>>> To make changes to your subscription:
>>>>> http://www.postgresql.org/mailpref/pgadmin-hackers
>>>>>
>>>>>
>>>>
>>>
>>
>
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/templates/foreign_tables/js/foreign_tables.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/templates/foreign_tables/js/foreign_tables.js
index 5f3dc69..b7df585 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/templates/foreign_tables/js/foreign_tables.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/templates/foreign_tables/js/foreign_tables.js
@@ -101,34 +101,56 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
         cell: 'string', group: '{{ _('Definition') }}',
         type: 'int', deps: ['datatype'],
         disabled: function(m) {
-        // We will store type from selected from combobox
+          var val = m.get('typlen');
+          // We will store type from selected from combobox
           if(!(_.isUndefined(m.get('inheritedid'))
             || _.isNull(m.get('inheritedid'))
             || _.isUndefined(m.get('inheritedfrom'))
-            || _.isNull(m.get('inheritedfrom')))) { return true; }
+            || _.isNull(m.get('inheritedfrom')))) {
 
-        var of_type = m.get('datatype');
-        if(m.type_options) {
-          m.set('is_tlength', false, {silent: true});
+            if (!_.isUndefined(val)) {
+              setTimeout(function() {
+                m.set('typlen', undefined);
+              }, 10);
+            }
+            return true;
+          }
+
+          var of_type = m.get('datatype'),
+              has_length = false;
+          if(m.type_options) {
+            m.set('is_tlength', false, {silent: true});
 
-          // iterating over all the types
-          _.each(m.type_options, function(o) {
-            // if type from selected from combobox matches in options
-            if ( of_type == o.value ) {
-                 m.set('typlen', undefined);
+            // iterating over all the types
+            _.each(m.type_options, function(o) {
+              // if type from selected from combobox matches in options
+              if ( of_type == o.value ) {
                 // if length is allowed for selected type
                 if(o.length)
                 {
                   // set the values in model
+                  has_length = true;
                   m.set('is_tlength', true, {silent: true});
                   m.set('min_val', o.min_val, {silent: true});
                   m.set('max_val', o.max_val, {silent: true});
                 }
+              }
+            });
+
+            if (!has_length && !_.isUndefined(val)) {
+              setTimeout(function() {
+                m.set('typlen', undefined);
+              }, 10);
             }
-          });
-          return !(m.get('is_tlength'));
-        }
-        return true;
+
+            return !(m.get('is_tlength'));
+          }
+          if (!has_length && !_.isUndefined(val)) {
+              setTimeout(function() {
+                m.set('typlen', undefined);
+              }, 10);
+            }
+          return true;
         },
         cellHeaderClasses: 'width_percent_10'
       },{
@@ -136,33 +158,54 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
         type: 'int', deps: ['datatype'],
         cell: 'string', group: '{{ _('Definition') }}',
         disabled: function(m) {
+          var val = m.get('precision');
           if(!(_.isUndefined(m.get('inheritedid'))
             || _.isNull(m.get('inheritedid'))
             || _.isUndefined(m.get('inheritedfrom'))
-            || _.isNull(m.get('inheritedfrom')))) { return true; }
+            || _.isNull(m.get('inheritedfrom')))) {
+
+            if (!_.isUndefined(val)) {
+              setTimeout(function() {
+                m.set('precision', undefined);
+              }, 10);
+            }
+            return true;
+          }
+
+          var of_type = m.get('datatype'),
+              has_precision = false;
 
-          var of_type = m.get('datatype');
           if(m.type_options) {
              m.set('is_precision', false, {silent: true});
             // iterating over all the types
             _.each(m.type_options, function(o) {
               // if type from selected from combobox matches in options
               if ( of_type == o.value ) {
-                m.set('precision', undefined);
                 // if precession is allowed for selected type
                 if(o.precision)
                 {
+                  has_precision = true;
                   // set the values in model
                   m.set('is_precision', true, {silent: true});
                   m.set('min_val', o.min_val, {silent: true});
                   m.set('max_val', o.max_val, {silent: true});
                 }
+              }
+            });
+            if (!has_precision && !_.isUndefined(val)) {
+              setTimeout(function() {
+                m.set('precision', undefined);
+              }, 10);
             }
-          });
-          return !(m.get('is_precision'));
-        }
-        return true;
-        }, cellHeaderClasses: 'width_percent_10'
+            return !(m.get('is_precision'));
+          }
+          if (!has_precision && !_.isUndefined(val)) {
+            setTimeout(function() {
+              m.set('precision', undefined);
+            }, 10);
+          }
+          return true;
+      }, cellHeaderClasses: 'width_percent_10'
       },{
         id: 'typdefault', label:'{{ _('Default') }}', type: 'text',
         cell: 'string', min_version: 90300, group: '{{ _('Definition') }}',
@@ -216,22 +259,23 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
           min_version: 90200
       }],
     validate: function() {
-      var err = {},
-      errmsg;
+      var errmsg = null;
 
       if (_.isUndefined(this.get('attname')) || String(this.get('attname')).replace(/^\s+|\s+$/g, '') == '') {
-        err['name'] = '{{ _('Column Name cannot be empty!') }}';
-        errmsg = errmsg || err['attname'];
+        errmsg = '{{ _('Column Name cannot be empty!') }}';
+        this.errorModel.set('attname', errmsg);
+      } else {
+        this.errorModel.unset('attname');
       }
 
       if (_.isUndefined(this.get('datatype')) || String(this.get('datatype'))
       .replace(/^\s+|\s+$/g, '') == '') {
-        err['basensp'] = '{{ _('Column Datatype cannot be empty!') }}';
-        errmsg = errmsg || err['datatype'];
+        errmsg = '{{ _('Column Datatype cannot be empty!') }}';
+        this.errorModel.set('datatype', errmsg);
+      } else {
+        this.errorModel.unset('datatype');
       }
 
-      this.errorModel.clear().set(err);
-
       return errmsg;
     },
     is_editable_column: function(m) {
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/templates/sequence/js/sequence.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/templates/sequence/js/sequence.js
index 2fb7ae5..1b9db50 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/templates/sequence/js/sequence.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/templates/sequence/js/sequence.js
@@ -153,7 +153,10 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
           min: 1
         },{
           id: 'start', label: '{{ _('Start') }}', type: 'int',
-          mode: ['properties', 'create'], group: '{{ _('Definition') }}'
+          mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}',
+          disabled: function(m) {
+            return !m.isNew();
+          }
         },{
           id: 'minimum', label: '{{ _('Minimum') }}', type: 'int',
           mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
@@ -199,14 +202,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
               minimum = this.get('minimum'),
               maximum = this.get('maximum');
               start = this.get('start');
-          // Clear any existing error msg.
-          this.errorModel.clear();
 
           if (_.isUndefined(this.get('name'))
               || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
             msg = '{{ _('Name cannot be empty.') }}';
             this.errorModel.set('name', msg);
             return msg;
+          } else {
+            this.errorModel.unset('name');
           }
 
           if (_.isUndefined(this.get('seqowner'))
@@ -214,6 +217,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
             msg = '{{ _('Owner cannot be empty.') }}';
             this.errorModel.set('seqowner', msg);
             return msg;
+          } else {
+            this.errorModel.unset('seqowner');
           }
 
           if (_.isUndefined(this.get('schema'))
@@ -221,26 +226,81 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
             msg = '{{ _('Schema cannot be empty.') }}';
             this.errorModel.set('schema', msg);
             return msg;
+          } else {
+            this.errorModel.unset('schema');
+          }
+
+          if (!this.isNew()) {
+            if (_.isUndefined(this.get('current_value'))
+              || String(this.get('current_value')).replace(/^\s+|\s+$/g, '') == '') {
+              msg = '{{ _('Current value cannot be empty.') }}';
+              this.errorModel.set('current_value', msg);
+              return msg;
+            } else {
+              this.errorModel.unset('current_value');
+            }
+
+            if (_.isUndefined(this.get('increment'))
+              || String(this.get('increment')).replace(/^\s+|\s+$/g, '') == '') {
+              msg = '{{ _('Increment value cannot be empty.') }}';
+              this.errorModel.set('increment', msg);
+              return msg;
+            } else {
+              this.errorModel.unset('increment');
+            }
+
+            if (_.isUndefined(this.get('minimum'))
+              || String(this.get('minimum')).replace(/^\s+|\s+$/g, '') == '') {
+              msg = '{{ _('Minimum value cannot be empty.') }}';
+              this.errorModel.set('minimum', msg);
+              return msg;
+            } else {
+              this.errorModel.unset('minimum');
+            }
+
+            if (_.isUndefined(this.get('maximum'))
+              || String(this.get('maximum')).replace(/^\s+|\s+$/g, '') == '') {
+              msg = '{{ _('Maximum value cannot be empty.') }}';
+              this.errorModel.set('maximum', msg);
+              return msg;
+            } else {
+              this.errorModel.unset('maximum');
+            }
+
+            if (_.isUndefined(this.get('cache'))
+              || String(this.get('cache')).replace(/^\s+|\s+$/g, '') == '') {
+              msg = '{{ _('Cache value cannot be empty.') }}';
+              this.errorModel.set('cache', msg);
+              return msg;
+            } else {
+              this.errorModel.unset('cache');
+            }
           }
 
           var min_lt = '{{ _('Minimum value must be less than maximum value.') }}',
               start_lt = '{{ _('Start value cannot be less than minimum value.') }}',
               start_gt = '{{ _('Start value cannot be greater than maximum value.') }}';
+
           if ((minimum == 0 && maximum == 0) ||
               (parseInt(minimum, 10) >= parseInt(maximum, 10))) {
-            msg = min_lt
-            this.errorModel.set('minimum', msg);
-            return msg;
+            this.errorModel.set('minimum', min_lt);
+            return min_lt;
+          } else {
+            this.errorModel.unset('minimum');
           }
-          else if (start < minimum) {
-            msg = start_lt
-            this.errorModel.set('start', msg);
-            return msg;
+
+          if (start && minimum && parseInt(start) < parseInt(minimum)) {
+            this.errorModel.set('start', start_lt);
+            return start_lt;
+          } else {
+            this.errorModel.unset('start');
           }
-          else if (start > maximum) {
-            msg = start_gt
-            this.errorModel.set('start', msg);
-            return msg;
+
+          if (start && maximum && parseInt(start) > parseInt(maximum)) {
+            this.errorModel.set('start', start_gt);
+            return start_gt;
+          } else {
+            this.errorModel.unset('start');
           }
           return null;
         }
diff --git a/web/pgadmin/browser/server_groups/servers/resource_groups/templates/resource_groups/js/resource_groups.js b/web/pgadmin/browser/server_groups/servers/resource_groups/templates/resource_groups/js/resource_groups.js
index 3cc822e..26e63bf 100644
--- a/web/pgadmin/browser/server_groups/servers/resource_groups/templates/resource_groups/js/resource_groups.js
+++ b/web/pgadmin/browser/server_groups/servers/resource_groups/templates/resource_groups/js/resource_groups.js
@@ -85,54 +85,35 @@ define(
          */
         validate: function(keys) {
 
-          /* Check whether 'name' is present in 'keys', if it is present
-           * it means there is a change in that field from the GUI, so we
-           * need to validate it.
-           */
-          if (_.indexOf(keys, 'name') >= 0) {
-            var name = this.get('name');
-            if (_.isUndefined(name) || _.isNull(name) ||
-                String(name).replace(/^\s+|\s+$/g, '') == '') {
-              var msg = '{{ _('Name cannot be empty.') }}';
-              this.errorModel.set('name', msg);
-              return msg;
-            } else {
-              this.errorModel.unset('name');
-            }
+          var name = this.get('name');
+          if (_.isUndefined(name) || _.isNull(name) ||
+              String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name cannot be empty.') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
           }
 
-          /* Check whether 'cpu_rate_limit' is present in 'keys', if it is present
-           * it means there is a change in that field from the GUI, so we
-           * need to validate it.
-           */
-          if (_.indexOf(keys, 'cpu_rate_limit') >= 0) {
-            var cpu_rate_limit = this.get('cpu_rate_limit');
-            if (_.isUndefined(cpu_rate_limit) || _.isNull(cpu_rate_limit) ||
-                String(cpu_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
-              var msg = '{{ _('CPU rate limit cannot be empty.') }}';
-              this.errorModel.set('cpu_rate_limit', msg);
-              return msg;
-            } else {
-              this.errorModel.unset('cpu_rate_limit');
-            }
+          var cpu_rate_limit = this.get('cpu_rate_limit');
+          if (_.isUndefined(cpu_rate_limit) || _.isNull(cpu_rate_limit) ||
+              String(cpu_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('CPU rate limit cannot be empty.') }}';
+            this.errorModel.set('cpu_rate_limit', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('cpu_rate_limit');
           }
 
-          /* Check whether 'dirty_rate_limit' is present in 'keys', if it is present
-           * it means there is a change in that field from the GUI, so we
-           * need to validate it.
-           */
-          if (_.indexOf(keys, 'dirty_rate_limit') >= 0) {
-            var dirty_rate_limit = this.get('dirty_rate_limit');
-            if (_.isUndefined(dirty_rate_limit) || _.isNull(dirty_rate_limit) ||
-              String(dirty_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
-              var msg = '{{ _('Dirty rate limit cannot be empty.') }}';
-              this.errorModel.set('dirty_rate_limit', msg);
-              return msg;
-            } else {
-              this.errorModel.unset('dirty_rate_limit');
-            }
+          var dirty_rate_limit = this.get('dirty_rate_limit');
+          if (_.isUndefined(dirty_rate_limit) || _.isNull(dirty_rate_limit) ||
+            String(dirty_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Dirty rate limit cannot be empty.') }}';
+            this.errorModel.set('dirty_rate_limit', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('dirty_rate_limit');
           }
-
           return null;
         }
       })
diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/role/js/role.js b/web/pgadmin/browser/server_groups/servers/roles/templates/role/js/role.js
index a85416c..c74cd59 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/templates/role/js/role.js
+++ b/web/pgadmin/browser/server_groups/servers/roles/templates/role/js/role.js
@@ -427,7 +427,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backform) {
           deps: ['rolcanlogin'], options: {format: 'YYYY-MM-DD HH:mm:ss Z'}
         },{
           id: 'rolconnlimit',  type: 'int', group: '{{ _('Definition') }}',
-          label: '{{ _('Connection limit') }}', cell: 'number',
+          label: '{{ _('Connection limit') }}', cell: 'number', min : -1,
           mode: ['properties', 'edit', 'create'], disabled: 'readonly'
         },{
           id: 'rolcanlogin', label:'{{ _('Can login?') }}', type: 'switch',
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
index 9eb82b8..bf28474 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
@@ -727,6 +727,9 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
           check_for_empty(
             'username', '{{ _('Username must be specified.') }}'
           );
+          check_for_empty(
+            'port', '{{ _('Port must be specified.') }}'
+          );
           this.errorModel.set(err);
 
           if (_.size(err)) {
diff --git a/web/pgadmin/browser/static/js/datamodel.js b/web/pgadmin/browser/static/js/datamodel.js
index 5b1c3a7..c3b5fac 100644
--- a/web/pgadmin/browser/static/js/datamodel.js
+++ b/web/pgadmin/browser/static/js/datamodel.js
@@ -1,6 +1,6 @@
 define(
-   ['underscore', 'pgadmin', 'jquery', 'backbone'],
-function(_, pgAdmin, $, Backbone) {
+   ['underscore', 'underscore.string', 'pgadmin', 'jquery', 'backbone'],
+function(_, S, pgAdmin, $, Backbone) {
   var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
 
   pgBrowser.DataModel = Backbone.Model.extend({
@@ -136,6 +136,7 @@ function(_, pgAdmin, $, Backbone) {
         }
 
         self.sessAttrs = {};
+        self.fieldData = {};
         self.origSessAttrs = {};
         self.objects = [];
         self.arrays = [];
@@ -153,6 +154,23 @@ function(_, pgAdmin, $, Backbone) {
             _.each(schema, function(s) {
 
               switch(s.type) {
+                case 'int':
+                case 'numeric':
+                  self.fieldData[s.id] = {
+                    label: s.id,
+                    type: s.type,
+                    min: s.min || undefined,
+                    max: s.max || undefined
+                  }
+                  break;
+                default:
+                  self.fieldData[s.id] = {
+                      label: s.id,
+                      type: s.type
+                    }
+              }
+
+              switch(s.type) {
                 case 'array':
                   self.arrays.push(s.id);
 
@@ -280,6 +298,12 @@ function(_, pgAdmin, $, Backbone) {
       },
       sessValid: function() {
         var self = this;
+        // Perform default validations.
+        if ('default_validate' in self && typeof(self.default_validate) == 'function' &&
+            _.isString(self.default_validate())) {
+          return false;
+        }
+
         if ('validate' in self && _.isFunction(self.validate) &&
             _.isString(self.validate.apply(self))) {
           return false;
@@ -301,8 +325,9 @@ function(_, pgAdmin, $, Backbone) {
         }
 
         if (key != null && res) {
-          var attrs = {};
-          var self = this;
+          var attrs = {},
+              self = this,
+              msg;
 
           attrChanged = function(v, k) {
             if (k in self.objects) {
@@ -327,9 +352,18 @@ function(_, pgAdmin, $, Backbone) {
           if (!options || !options.silent) {
             self.trigger('change', self, options);
           }
+
+          // Perform default validations.
+
+          if ('default_validate' in self && typeof(self.default_validate) == 'function') {
+            msg = self.default_validate();
+          }
+
           if ('validate' in self && typeof(self['validate']) === 'function') {
 
-            var msg = self.validate(_.keys(attrs));
+            if (!msg) {
+              msg = self.validate(_.keys(attrs));
+            }
 
             /*
              * If any parent present, we will need to inform the parent - that
@@ -562,6 +596,13 @@ function(_, pgAdmin, $, Backbone) {
 
           var msg = null,
               validate = function(m, attrs) {
+                if ('default_validate' in m && typeof(m.default_validate) == 'function') {
+                  msg = m.default_validate();
+                  if (_.isString(msg)) {
+                    return msg;
+                  }
+                }
+
                 if ('validate' in m && typeof(m.validate) == 'function') {
                   msg = m.validate(attrs);
 
@@ -655,6 +696,79 @@ function(_, pgAdmin, $, Backbone) {
         });
 
         self.trigger('pgadmin-session:stop');
+      },
+      default_validate: function() {
+        var msg, field, value, type;
+
+        for (var i = 0, keys = _.keys(this.attributes), l = keys.length;
+                 i<l;
+                 i++) {
+
+          value = this.attributes[keys[i]];
+          field  = this.fieldData[keys[i]]
+          msg = null;
+
+          if (!(_.isUndefined(value) || _.isNull(value) ||
+                String(value).replace(/^\s+|\s+$/g, '') == '')) {
+
+            if (!field) {
+              continue;
+            }
+
+            type = field.type || undefined;
+            if (!type) {
+              continue;
+            }
+
+            switch(type) {
+              case 'int':
+                msg = this.integer_validate(value, field);
+                break;
+              case 'numeric':
+                msg = this.number_validate(value, field);
+                break;
+            }
+
+            if (msg) {
+              this.errorModel.set(field.label, msg);
+              return msg;
+            } else {
+              this.errorModel.unset(field.label);
+            }
+          } else {
+            if (field) {
+              this.errorModel.unset(field.label);
+            }
+          }
+        }
+        return null;
+      },
+
+      check_min_max: function (value, field) {
+        var label = field.label,
+            min_value = field.min,
+            max_value =  field.max;
+
+        if (min_value && value < min_value) {
+          return S(pgAdmin.Browser.messages.MUST_GR_EQ).sprintf(label, min_value).value();
+        } else if (max_value && value > max_value) {
+          return S(pgAdmin.Browser.messages.MUST_LESS_EQ).sprintf(label, max_value).value();
+        }
+        return null;
+      },
+      number_validate: function (value, field) {
+        var pattern = new RegExp("^-?[0-9]+(\.?[0-9]*)?$");
+        if (!pattern.test(value)) {
+          return S(pgAdmin.Browser.messages.MUST_BE_NUM).sprintf(field.label).value()
+        }
+        return this.check_min_max(value, field)
+      },
+      integer_validate: function(value, field) {
+        var pattern = new RegExp("^-?[0-9]*$");
+        if (!pattern.test(value)) {
+          return S(pgAdmin.Browser.messages.MUST_BE_INT).sprintf(field.label).value()
+        }
+        return this.check_min_max(value, field)
       }
     });
 
@@ -696,7 +810,8 @@ function(_, pgAdmin, $, Backbone) {
         return self;
       },
       startNewSession: function() {
-        var self = this;
+        var self = this,
+            msg;
 
         if (self.trackChanges) {
           // We're stopping the existing session.
@@ -718,8 +833,15 @@ function(_, pgAdmin, $, Backbone) {
           if ('startNewSession' in m && _.isFunction(m.startNewSession)) {
             m.startNewSession();
           }
-          if ('validate' in m && typeof(m.validate) === 'function') {
-            var msg = m.validate();
+
+          if ('default_validate' in m && typeof(m.default_validate) == 'function') {
+            msg = m.default_validate();
+          }
+
+          if (_.isString(msg)) {
+            self.sessAttrs['invalid'][m.cid] = msg;
+          } else if ('validate' in m && typeof(m.validate) === 'function') {
+            msg = m.validate();
 
             if (msg) {
               self.sessAttrs['invalid'][m.cid] = msg;
@@ -900,7 +1022,14 @@ function(_, pgAdmin, $, Backbone) {
 
           (self.handler || self).trigger('pgadmin-session:added', self, obj);
 
-          if ('validate' in obj && typeof(obj.validate) === 'function') {
+
+          if ('default_validate' in obj && typeof(obj.default_validate) == 'function') {
+            msg = obj.default_validate();
+          }
+
+          if (_.isString(msg)) {
+            (self.sessAttrs['invalid'])[obj.cid] = msg;
+          } else if ('validate' in obj && typeof(obj.validate) === 'function') {
             msg = obj.validate();
 
             if (msg) {
@@ -908,7 +1037,14 @@ function(_, pgAdmin, $, Backbone) {
             }
           }
         } else {
-          if ('validate' in obj && typeof(obj.validate) === 'function') {
+
+          if ('default_validate' in obj && typeof(obj.default_validate) == 'function') {
+            msg = obj.default_validate();
+          }
+
+          if (_.isString(msg)) {
+            (self.sessAttrs['invalid'])[obj.cid] = msg;
+          } else if ('validate' in obj && typeof(obj.validate) === 'function') {
             msg = obj.validate();
 
             if (msg) {
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 553676e..13823b7 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -57,7 +57,7 @@
     });
 
   var controlMapper = Backform.controlMapper = {
-    'int': ['uneditable-input', 'integer', 'integer'],
+    'int': ['uneditable-input', 'numeric', 'numeric'],
     'text': ['uneditable-input', 'input', 'string'],
     'numeric': ['uneditable-input', 'numeric', 'numeric'],
     'date': 'datepicker',
@@ -1493,109 +1493,6 @@
     }
 });
 
-  /*
-   * Integer input Control functionality just like backgrid
-   */
-  var IntegerControl = Backform.IntegerControl = Backform.InputControl.extend({
-    defaults: {
-      type: "number",
-      label: "",
-      min: undefined,
-      max: undefined,
-      maxlength: 255,
-      extraClasses: [],
-      helpMessage: null
-    },
-    template: _.template([
-      '<label class="<%=Backform.controlLabelClassName%>"><%=label%></label>',
-      '<div class="<%=Backform.controlsClassName%>">',
-      '  <input type="<%=type%>" class="<%=Backform.controlClassName%> <%=extraClasses.join(\' \')%>" name="<%=name%>" min="<%=min%>" max="<%=max%>"maxlength="<%=maxlength%>" value="<%-value%>" placeholder="<%-placeholder%>" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> />',
-      '  <% if (helpMessage && helpMessage.length) { %>',
-      '    <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
-      '  <% } %>',
-      '</div>'
-    ].join("\n")),
-    events: {
-      "change input": "checkInt",
-      "focus input": "clearInvalid"
-    },
-    checkInt: function(e) {
-      var field = _.defaults(this.field.toJSON(), this.defaults),
-          attrArr = this.field.get("name").split('.'),
-          name = attrArr.shift(),
-          value = this.getValueFromDOM(),
-          min_value = field.min,
-          max_value = field.max,
-          isValid = true,
-          intPattern = new RegExp("^-?[0-9]*$"),
-          isMatched = intPattern.test(value);
-
-      // Below logic will validate input
-      if (!isMatched) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_BE_INT).sprintf(
-              field.label
-              ).value()
-            );
-      }
-
-      // Below will check if entered value is in-between min & max range
-      if (isValid && (!_.isUndefined(min_value) && value < min_value)) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_GR_EQ).sprintf(
-              field.label,
-              min_value
-              ).value()
-            );
-      }
-
-      if (isValid && (!_.isUndefined(max_value) && value > max_value)) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_LESS_EQ).sprintf(
-              field.label,
-              max_value
-              ).value()
-            );
-      }
-
-      // After validation we need to set that value into model (only if all flags are true)
-      if (isValid) {
-        this.stopListening(this.model, "change:" + name, this.render);
-        this.model.errorModel.unset(name);
-        this.model.set(name, value);
-        this.listenTo(this.model, "change:" + name, this.render);
-        if (this.model.collection || this.model.handler) {
-          (this.model.collection || this.model.handler).trigger(
-             'pgadmin-session:model:valid', this.model, (this.model.collection || this.model.handler)
-            );
-        } else {
-          (this.model).trigger(
-             'pgadmin-session:valid', this.model.sessChanged(), this.model
-            );
-        }
-      } else {
-        if (this.model.collection || this.model.handler) {
-          (this.model.collection || this.model.handler).trigger(
-             'pgadmin-session:model:invalid', this.model.errorModel.get(name), this.model
-            );
-        } else {
-          (this.model).trigger(
-             'pgadmin-session:invalid', this.model.errorModel.get(name), this.model
-            );
-        }
-      }
-    }
-  });
-
    /*
    * Numeric input Control functionality just like backgrid
    */
@@ -1617,86 +1514,7 @@
       '    <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
       '  <% } %>',
       '</div>'
-    ].join("\n")),
-    events: {
-      "change input": "checkNumeric",
-      "focus input": "clearInvalid"
-    },
-    checkNumeric: function(e) {
-      var field = _.defaults(this.field.toJSON(), this.defaults),
-          attrArr = this.field.get("name").split('.'),
-          name = attrArr.shift(),
-          value = this.getValueFromDOM(),
-          min_value = field.min,
-          max_value = field.max,
-          isValid = true,
-          intPattern = new RegExp("^-?[0-9]+(\.?[0-9]*)?$"),
-          isMatched = intPattern.test(value);
-
-      // Below logic will validate input
-      if (!isMatched) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_BE_NUM).sprintf(
-              field.label
-              ).value()
-            );
-      }
-
-      // Below will check if entered value is in-between min & max range
-      if (isValid && (!_.isUndefined(min_value) && value < min_value)) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_GR_EQ).sprintf(
-              field.label,
-              min_value
-              ).value()
-            );
-      }
-
-      if (isValid && (!_.isUndefined(max_value) && value > max_value)) {
-        isValid = false;
-        this.model.errorModel.unset(name);
-        this.model.errorModel.set(
-            name,
-            S(pgAdmin.Browser.messages.MUST_LESS_EQ).sprintf(
-              field.label,
-              max_value
-              ).value()
-            );
-      }
-
-      // After validation we need to set that value into model (only if all flags are true)
-      if (isValid) {
-        this.stopListening(this.model, "change:" + name, this.render);
-        this.model.errorModel.unset(name);
-        this.model.set(name, value);
-        this.listenTo(this.model, "change:" + name, this.render);
-        if (this.model.collection || this.model.handler) {
-          (this.model.collection || this.model.handler).trigger(
-             'pgadmin-session:model:valid', this.model, (this.model.collection || this.model.handler)
-            );
-        } else {
-          (this.model).trigger(
-             'pgadmin-session:valid', this.model.sessChanged(), this.model
-            );
-        }
-      } else {
-        if (this.model.collection || this.model.handler) {
-          (this.model.collection || this.model.handler).trigger(
-             'pgadmin-session:model:invalid', this.model.errorModel.get(name), this.model
-            );
-        } else {
-          (this.model).trigger(
-             'pgadmin-session:invalid', this.model.errorModel.get(name), this.model
-            );
-        }
-      }
-    }
+    ].join("\n"))
   });
 
   ///////
-- 
Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

Reply via email to