public inbox for [email protected]  
help / color / mirror / Atom feed
From: Harshal Dhumal <[email protected]>
To: Ashesh Vashi <[email protected]>
Cc: [email protected]
Subject: Variable control patch
Date: Thu, 7 Jan 2016 13:04:32 +0530
Message-ID: <CAFiP3vy4iZ_hiNhGJBYcZZnV-td=7K=hQLRgvKyrPHai0LSfzQ@mail.gmail.com> (raw)
List-Unsubscribe:  <mailto:[email protected]?body=unsub%20pgadmin-hackers>

Hi,
Please find attached patch for Variable control.

Usage:
1] In variables tab

id: 'spcoptions', label: 'Variables', type: 'collection', group: "Variables",
model: pgAdmin.Browser.Node.VariableModel, control:
'variable-collection', mode: [ 'edit', 'create'],
canAdd: true, canDelete: true, uniqueCol : ['name'],
variableCol : 'name', url: "getvars",

2] In database tab

id: 'spcoptions', label: 'Variables', type: 'collection', group: "Variables",
model: pgAdmin.Browser.Node.VariableModel.extend({hasDatabase:true}),
control: 'variable-collection', mode: [ 'edit', 'create'],
canAdd: true, canDelete: true, uniqueCol : ['name','database'],
variableCol : 'name', url: "getvars",


3] In Use roles tab

id: 'spcoptions', label: 'Variables', type: 'collection', group: "Variables",
model: pgAdmin.Browser.Node.VariableModel.extend({hasRole:true}),
control: 'variable-collection', mode: [ 'edit', 'create'],
canAdd: true, canDelete: true, uniqueCol : ['name','role'],
variableCol : 'name', url: "getvars",


-- 
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers


Attachments:

  [text/x-patch] variable_control_7_Jan.patch (26.1K, 3-variable_control_7_Jan.patch)
  download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index d478526..0604202 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -97,6 +97,11 @@ class ServerModule(sg.ServerGroupPluginModule):
             'name': 'pgadmin.browser.server.privilege',
             'path': url_for('browser.index') + 'server/static/js/privilege',
             'when': self.node_type
+            },
+            {
+            'name': 'pgadmin.browser.server.variable',
+            'path': url_for('browser.index') + 'server/static/js/variable',
+            'when': self.node_type
             }])
 
         for module in self.submodules:
diff --git a/web/pgadmin/browser/server_groups/servers/static/js/variable.js b/web/pgadmin/browser/server_groups/servers/static/js/variable.js
new file mode 100644
index 0000000..3d8353d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/static/js/variable.js
@@ -0,0 +1,422 @@
+(function(root, factory) {
+  // Set up Backform appropriately for the environment. Start with AMD.
+  if (typeof define === 'function' && define.amd) {
+    define(['underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify', 'pgadmin.browser.node'],
+     function(_, $, Backbone, Backform, Backgrid, Alertify, pgNode) {
+      // Export global even in AMD case in case this script is loaded with
+      // others that may still expect a global Backform.
+      return factory(root, _, $, Backbone, Backform, Alertify, pgNode);
+    });
+
+  // Next for Node.js or CommonJS. jQuery may not be needed as a module.
+  } else if (typeof exports !== 'undefined') {
+    var _ = require('underscore') || root._,
+      $ = root.jQuery || root.$ || root.Zepto || root.ender,
+      Backbone = require('backbone') || root.Backbone,
+      Backform = require('backform') || root.Backform;
+      Alertify = require('alertify') || root.Alertify;
+      pgAdmin = require('pgadmin.browser.node') || root.pgAdmin.Browser.Node;
+    factory(root, _, $, Backbone, Backform, Alertify, pgNode);
+
+  // Finally, as a browser global.
+  } else {
+    factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.pgAdmin.Browser.Node);
+  }
+} (this, function(root, _, $, Backbone, Backform, Alertify, pgNode) {
+  /**
+   *  Variablemodel used to represent configuration parameters (variables tab) for database objects.
+   *
+   **/
+
+  var VariableModel = pgNode.VariableModel = pgNode.Model.extend({
+    hasDatabase : false,
+
+    hasRole : false,
+
+    defaults: {
+      name: undefined,
+      value: undefined,
+      role: undefined,
+      database: undefined,
+
+      /*
+       * The following information can be used to render the dynamic
+       * controls. It has nothing to with the data.
+       *
+       * These data needs to be fill in by the Variable Dynamic Control.
+       */
+      vartype: undefined,
+      max_val: undefined,
+      min_val: undefined,
+      enumvals: []
+    },
+    initialize: function(val, opts) {
+        pgNode.Model.prototype.initialize(arguments);
+        if (typeof val === 'string') {
+            var idx = val.indexOf('=');
+            this.set('name',idx > 0 ? val.substring(0, idx):'', {silent:true});
+            this.set('value',idx > 0 ? val.substring(idx+1):'', {silent:true});
+        }
+    },
+    schema: [
+      {id: 'name', label:'Name', type:'text', editable: false},
+      {id: 'value', label:'Value', type: 'text', cell: 'dynamic-variable', editable: true},
+      {id: 'database', label:'Database', type: 'select2', editable: true},
+      {id: 'role', label:'Role', type: 'select2', editable: true}
+    ],
+    toJSON: function() {
+      var d = Backbone.Model.prototype.toJSON.apply(this);
+      // Remove metadata before returning model values.
+      if (!this.hasDatabase) {
+        delete d.database;
+      }
+      if (!this.hasRole) {
+        delete d.role;
+      }
+      delete d.vartype;
+      delete d.max_val;
+      delete d.min_val;
+      delete d.enumvals;
+      return d;
+    }
+  });
+
+  /*
+   * Dynamic Variable cell. Used for variable data type column in Variables tab.
+   * Behaviour of cell depends on variable data type.
+   */
+  var DynamicVariableCell = Backgrid.Extension.DynamicVariableCell = Backgrid.Cell.extend({
+    /*
+     * Mapping of postgres data type to backgrid cell type.
+     */
+    variableCellMapper: {
+      "bool":Backgrid.Extension.SwitchCell,
+      "enum":Backgrid.Extension.Select2Cell,
+      "string":Backgrid.Cell,
+      "integer":Backgrid.IntegerCell,
+      "real":Backgrid.NumberCell
+    },
+
+    initialize: function () {
+
+      var vartype = this.model.get("vartype"),
+          cell = this.variableCellMapper[vartype] || Backgrid.Cell,
+          self = this;
+      /*
+       * Set properties for dynamic cell.
+       */
+      _.each(cell.prototype, function(v,k) {
+        self[k] = v;
+      });
+
+      DynamicVariableCell.__super__.initialize.apply(this, arguments);
+
+      switch(vartype) {
+        case "bool":
+          // There are no specific properties for BooleanCell.
+        break;
+        case "enum":
+          var options = [],
+            enumvals = this.model.get("enumvals");
+          _.each(enumvals, function(enumval) {
+            options.push([enumval,enumval]);
+          });
+          this.optionValues = options;
+          this.multiple = cell.prototype.multiple;
+          this.delimiter = cell.prototype.delimiter;
+          this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
+            if (column.get("name") == this.column.get("name")) {
+              editor.setOptionValues(this.optionValues);
+              editor.setMultiple(this.multiple);
+            }
+          });
+        break;
+        case "integer":
+          this.decimals = 0;
+          this.decimalSeparator = cell.prototype.decimalSeparator;
+          this.orderSeparator = cell.prototype.orderSeparator;
+          var formatter = this.formatter;
+          formatter.decimals = this.decimals;
+          formatter.decimalSeparator = this.decimalSeparator;
+          formatter.orderSeparator = this.orderSeparator;
+          break;
+        case "real":
+          this.decimals = cell.prototype.decimals;
+          this.decimalSeparator = cell.prototype.decimalSeparator;
+          this.orderSeparator = cell.prototype.orderSeparator;
+          var formatter = this.formatter;
+          formatter.decimals = this.decimals;
+          formatter.decimalSeparator = this.decimalSeparator;
+          formatter.orderSeparator = this.orderSeparator;
+          break;
+        case "string":
+        default:
+          // There are no specific properties for StringCell and Cell.
+      }
+    }
+  });
+
+  /**
+   * Variable Tab Control to set/update configuration values for database object.
+   *
+   **/
+  var VariableCollectionControl =  Backform.VariableCollectionControl = Backform.UniqueColCollectionControl.extend({
+    hasDatabase : false,
+
+    hasRole : false,
+
+    initialize: function() {
+      Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
+      // Check if variableCol column name is provided.
+      if (!this.field.get('variableCol')) {
+          errorMsg = "Developer: 'variableCol' column name is not provided."
+          alert (errorMsg);
+          return null;
+      }
+
+      var collection = this.model.get(this.field.get("name"));
+      this.hasDatabase = collection.model.prototype.hasDatabase;
+      this.hasRole = collection.model.prototype.hasRole;
+      if (this.hasDatabase && this.hasRole){
+        alert('Developer: Both Database and Role columns can not be used together in `VariableCollectionControl`.');
+        return;
+      }
+
+      // get all available variable options for database object.
+      this.getVariableOptions();
+      /*
+       * Set the metadata vartype, min_var, max_var, enumvals for each model.
+       */
+      if (collection) {
+        collection.each(function(m) {
+          self.parseAndSetModelMetadata(m);
+        });
+      }
+    },
+    /*
+     * Get the variable options for this control.
+     */
+    getVariableOptions: function() {
+      self = this;
+      if (this.field.get('url')) {
+        var node = this.field.get('node'),
+            full_url = node.generate_url.apply(
+                            node, [
+                            null, this.field.get('url'), this.field.get('node_data'), true,
+                            this.field.get('node_info')
+                            ]);
+        $.ajax({
+          async: false,
+          url: full_url,
+        }).done(function (data) {
+          self.field.set("options",data.data);
+        });
+      }
+    },
+    /*
+     * Add the additional variable metadata to model instance.
+     * This metadata will be used to identify correct control for cell, cell value options,
+     * min value range and max value range.
+     */
+    parseAndSetModelMetadata: function(m) {
+      var availableVars = self.field.get("options") || [],
+        variableCol = self.field.get("variableCol"),
+        varName = m.get(variableCol),
+        modelData = {};
+
+      _.each(availableVars, function(v) {
+              if(varName == v[variableCol]) {
+                modelData["vartype"] = v["vartype"] || undefined;
+                modelData["max_val"] = v["max_val"] || undefined;
+                modelData["min_val"] = v["min_val"] || undefined;
+                modelData["enumvals"] = v["enumvals"] || undefined;
+
+                var val = m.get("value");
+                // Parse numeric values.
+                if (modelData["vartype"] == "integer" && !!val) {
+                  modelData["value"] = parseInt(val);
+                } else if(modelData["vartype"] == "real" && !!val) {
+                  modelData["value"] = parseFloat(val);
+                }
+              }
+            });
+
+      m.set(modelData, {silent: true});
+    },
+    getHeaderForm: function(){
+      if(this.hasDatabase){
+        return $(["<div class='subnode-header-form'>",
+            "<div class='container-fluid'>",
+              "<div class='row'>",
+                "<div class='col-md-4'>",
+                  "<label class='control-label'>Variable name</label>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<select class='form-control' name='variable'></select>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<button class='btn-sm btn-default add'>Add</buttton>",
+                "</div>",
+              "</div>",
+              "<div class='row'>",
+                "<div class='col-md-4'>",
+                  "<label class='control-label'>Database</label>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<select class='form-control' name='database'></select>",
+                "</div>",
+              "<div>",
+            "</div>",
+          "</div>"].join("\n"));
+      } else if (this.hasRole) {
+        return $(["<div class='subnode-header-form'>",
+            "<div class='container-fluid'>",
+              "<div class='row'>",
+                "<div class='col-md-4'>",
+                  "<label class='control-label'>Variable name</label>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<select class='form-control' name='variable'></select>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<button class='btn-sm btn-default add'>Add</buttton>",
+                "</div>",
+              "</div>",
+              "<div class='row'>",
+                "<div class='col-md-4'>",
+                  "<label class='control-label'>Role</label>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<select class='form-control' name='role'></select>",
+                "</div>",
+              "<div>",
+            "</div>",
+          "</div>"].join("\n"));
+      } else {
+        return $(["<div class='subnode-header-form'>",
+            "<div class='container-fluid'>",
+              "<div class='row'>",
+                "<div class='col-md-4'>",
+                  "<label class='control-label'>Variable name</label>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<select class='form-control' name='variable'></select>",
+                "</div>",
+                "<div class='col-md-4'>",
+                  "<button class='btn-sm btn-default add'>Add</buttton>",
+                "</div>",
+              "</div>",
+            "</div>",
+          "</div>"].join("\n"));
+      }
+    },
+    showGridControl: function(data) {
+      var self = this,
+          gridHeader = ["<div class='subnode-header'>",
+            "<label class='control-label'>" + data.label + "</label>",
+            "</div>"].join("\n"),
+          gridBody = $("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode'></div>").append(gridHeader),
+          gridHeaderForm = this.getHeaderForm();
+      gridBody.append(gridHeaderForm);
+      var $selectVariable = gridHeaderForm.find('select[name=variable]').empty(),
+          availableVars = self.field.get("options") || [];
+      _.each(availableVars, function(option) {
+        $selectVariable.append($("<option></option>")
+          .attr("value", option.name).text(option.name));
+      })
+
+      $selectVariable.select2();
+      if(this.hasDatabase) {
+        $selectDatabase = gridHeaderForm.find('select[name=database]').empty();
+        $selectDatabase.append($("<option value='a'>a</option><option value='b'>b</option>"));
+        $selectDatabase.select2();
+      } else if(this.hasRole) {
+        $selectRole = gridHeaderForm.find('select[name=role]').empty();
+        $selectRole.append($("<option value='a'>a</option><option value='b'>b</option>"));
+        $selectRole.select2();
+      }
+
+      var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
+          gridSchema = Backform.generateGridColumnsFromModel(
+            data.node_info, subnode, this.field.get('mode'), data.columns
+            ),
+          self = this;
+      // Set visibility of Add button
+      if (data.disabled || data.canAdd == false) {
+        $(gridBody).find("button.add").remove();
+      }
+
+      // Insert Delete Cell into Grid
+      if (data.disabled == false && data.canDelete) {
+          gridSchema.columns.unshift({
+            name: "pg-backform-delete", label: "",
+            cell: Backgrid.Extension.DeleteCell,
+            editable: false, cell_priority: -1
+          });
+      }
+
+      var collection = this.model.get(data.name);
+      // Initialize a new Grid instance
+      var gridcols = [];
+      _.each(gridSchema.columns, function(schema){
+        if (schema.name == 'database' || schema.name == 'role'){
+          if(self.hasDatabase && schema.name == 'database') {
+            gridcols.push(schema)
+          } else if (self.hasRole && schema.name == 'role') {
+            gridcols.push(schema)
+          }
+        } else {
+          gridcols.push(schema);
+        }
+      })
+      var grid = self.grid = new Backgrid.Grid({
+          columns: gridcols,
+          collection: collection,
+          className: "backgrid table-bordered"
+      });
+
+      // Render subNode grid
+      subNodeGrid = grid.render().$el;
+
+      // Combine Edit and Delete Cell
+      if (data.canDelete && data.canEdit) {
+        $(subNodeGrid).find("th.pg-backform-delete").remove();
+      }
+
+      $dialog =  gridBody.append(subNodeGrid);
+
+      // Add button callback
+      if (!(data.disabled || data.canAdd == false)) {
+        $dialog.find('button.add').first().click(function(e) {
+            e.preventDefault();
+            var varName = $selectVariable.val(),
+              variableCol = self.field.get("variableCol"),
+              modelData = {};
+              modelData[variableCol] = varName;
+            if(self.hasDatabase){
+              modelData['database'] = $selectDatabase.val();
+            } else if (self.hasRole){
+              modelData['role'] = $selectRole.val();
+            }
+
+            $(grid.body.$el.find($("tr.new"))).removeClass("new");
+
+            var m = new (self.field.get('model'))(modelData, {silent: true});
+            self.parseAndSetModelMetadata(m);
+            collection.add(m);
+            var idx = collection.indexOf(m);
+            // idx may not be always > -1 because our UniqueColCollection may remove 'm' if duplicate value found.
+            if (idx > -1) {
+              var newRow = grid.body.rows[idx].$el;
+              newRow.addClass("new");
+              $(newRow).pgMakeVisible('backform-tab');
+            }
+            return false;
+        });
+      }
+      return $dialog;
+    }
+  })
+
+  return VariableModel
+}));
diff --git a/web/pgadmin/browser/static/js/node.ui.js b/web/pgadmin/browser/static/js/node.ui.js
index 1412cc8..d385b6f 100644
--- a/web/pgadmin/browser/static/js/node.ui.js
+++ b/web/pgadmin/browser/static/js/node.ui.js
@@ -176,5 +176,50 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
     })
   });
 
+  /*
+   * Global function to make visible  particular dom element in it's parent
+   * with given class.
+   */
+  $.fn.pgMakeVisible = function( cls ) {
+    return this.each(function() {
+      if (!this || !$(this.length))
+        return;
+      var top, p = $(this), hasScrollbar = function(j) {
+        if (j && j.length > 0) {
+          return j.get(0).scrollHeight > j.height();
+        }
+        return false;
+      };
+
+      while(p) {
+        top = p.get(0).offsetTop + p.height();
+        p = p.parent();
+        if (hasScrollbar(p)) {
+          p.scrollTop(top);
+        }
+        if (p.hasClass(cls)) //'backform-tab'
+          return;
+      }
+    });
+  }
+
+  /*
+   *  Backform Select2AjaxOptions control.
+   */
+  var Select2AjaxOptionsControl = Backform.Select2AjaxOptionsControl = Backform.NodeAjaxOptionsControl.extend({
+    render: function() {
+
+      var options = this.field.get('options') || [];
+
+      Backform.NodeAjaxOptionsControl.prototype.render.apply(this, arguments);
+
+      var col = _.defaults(this.field.toJSON(), this.defaults)
+      /* Add empty option as Select2 requires any empty '<option><option>' for
+       * some of its functionality to work and initialize select2 control.
+       */
+      this.$el.find("select").append($('<option></option>').select2(col.select2);
+      return this;
+    }
+  });
   return Backform.NodeListControl;
 });
diff --git a/web/pgadmin/static/css/overrides.css b/web/pgadmin/static/css/overrides.css
index 6d0f662..3ec4d6f 100755
--- a/web/pgadmin/static/css/overrides.css
+++ b/web/pgadmin/static/css/overrides.css
@@ -611,3 +611,20 @@ table.backgrid tr.new {
     right: 0px;
     bottom :0;
 }
+.subnode-header-form {
+    background-color:#2c76b4;
+    color:#FFFFFF;
+    padding:3px 0 10px 0;
+}
+
+.subnode-header-form button.add {
+    float:right;
+    margin-right:15px;
+}
+
+.select2 {
+  width: 100% !important;
+}
+.select2-search__field, select{
+  background:inherit !important;
+}
\ No newline at end of file
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 35daaed..4893f45 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -74,7 +74,8 @@
     'multiline': ['textarea', 'textarea', 'string'],
     'collection': ['sub-node-collection', 'sub-node-collection', 'string'],
     'uniqueColCollection': ['unique-col-collection', 'unique-col-collection', 'string'],
-    'switch' : 'switch'
+    'switch' : 'switch',
+    'select2': 'select2',
   };
 
   var getMappedControl = Backform.getMappedControl = function(type, mode) {
@@ -589,7 +590,7 @@
         });
 
         // Check if unique columns provided are also in model attributes.
-        if (uniqueCol.length > _.intersection(columns, uniqueCol).length){
+        if (uniqueCol.length > _.intersection(columns, uniqueCol).length) {
             errorMsg = "Developer: Unique column/s [ "+_.difference(uniqueCol, columns)+" ] not found in collection model [ " + columns +" ]."
             alert (errorMsg);
         }
@@ -610,11 +611,11 @@
     collectionChanged: function(newModel, coll, op) {
         var uniqueCol = this.field.get('uniqueCol') || [],
             uniqueChangedAttr = [],
-            changedAttr = newModel.changedAttributes();
+            self = this;
         // Check if changed model attributes are also in unique columns. And then only check for uniqueness.
-        if (changedAttr) {
+        if (newModel.attributes) {
             _.each(uniqueCol, function(col) {
-                if ( _.has(changedAttr,col))
+                if ( _.has(newModel.attributes,col))
                 {
                    uniqueChangedAttr.push(col);
                 }
@@ -629,7 +630,9 @@
         var collection = this.model.get(this.field.get('name'));
         this.stopListening(collection, "change", this.collectionChanged);
         // Check if changed attribute's value of new/updated model also exist for another model in collection.
-        // If duplicate value exists then set the attribute's value of new/updated model to it's previous values.
+        // If duplicate value exists then set the attribute's value of new/updated model to its previous values.
+        var m = undefined,
+            oldModel = undefined;
         collection.each(function(model) {
             if (newModel != model) {
                 var duplicateAttrValues = []
@@ -639,12 +642,41 @@
                         duplicateAttrValues.push(attrValue)
                     }
                 });
-                if (duplicateAttrValues.length == uniqueCol.length){
-                     newModel.set(uniqueChangedAttr[0], newModel.previous(uniqueChangedAttr[0]), {silent: true});
-                     // TODO- Need to add notification in status bar for unique column.
+                if (duplicateAttrValues.length == uniqueCol.length) {
+                  m = newModel;
+                  // Keep reference of model to make it visible in dialog.
+                  oldModel = model;
                 }
             }
         });
+        if (m) {
+          if (op && op.add) {
+            // Remove duplicate model.
+            setTimeout(function() {
+              collection.remove(m);
+            }, 0);
+
+          } else {
+            /*
+             * Set model value to its previous value as its new value is
+             * conflicting with another model value.
+             */
+
+            m.set(uniqueChangedAttr[0], m.previous(uniqueChangedAttr[0]), {silent: true});
+          }
+          if (oldModel) {
+            var idx = collection.indexOf(oldModel);
+            if (idx > -1) {
+              var newRow = self.grid.body.rows[idx].$el;
+              newRow.addClass("new");
+              $(newRow).pgMakeVisible('backform-tab');
+              setTimeout(function() {
+                newRow.removeClass("new");
+                }, 3000);
+            }
+          }
+        }
+
         this.listenTo(collection, "change", this.collectionChanged);
     },
     render: function() {
@@ -709,7 +741,7 @@
 
       var collection = this.model.get(data.name);
       // Initialize a new Grid instance
-      var grid = new Backgrid.Grid({
+      var grid = self.grid = new Backgrid.Grid({
           columns: gridSchema.columns,
           collection: collection,
           className: "backgrid table-bordered"
@@ -733,18 +765,18 @@
 
             // If allowMultipleEmptyRows is not set or is false then don't allow second new empty row.
             // There should be only one empty row.
-            if (!allowMultipleEmptyRows && collection){
+            if (!allowMultipleEmptyRows && collection) {
                 var isEmpty = false;
-                collection.each(function(model){
+                collection.each(function(model) {
                     var modelValues = [];
-                    _.each(model.attributes, function(val, key){
+                    _.each(model.attributes, function(val, key) {
                         modelValues.push(val);
                     })
-                    if(!_.some(modelValues, _.identity)){
+                    if(!_.some(modelValues, _.identity)) {
                         isEmpty = true;
                     }
                 });
-                if(isEmpty){
+                if(isEmpty) {
                     return false;
                 }
             }
@@ -753,9 +785,10 @@
             var m = new (data.model)(null, {silent: true});
             collection.add(m);
 
-            var idx = collection.indexOf(m);
-            newRow = grid.body.rows[idx].$el;
+            var idx = collection.indexOf(m),
+              newRow = grid.body.rows[idx].$el;
             newRow.addClass("new");
+            $(newRow).pgMakeVisible('backform-tab');
             return false;
         });
       }
@@ -869,7 +902,7 @@
       }
 
       // Initialize a new Grid instance
-      var grid = new Backgrid.Grid({
+      var grid = self.grid = new Backgrid.Grid({
           columns: gridSchema.columns,
           collection: collection,
           className: "backgrid table-bordered"
@@ -890,10 +923,11 @@
       $dialog.find('button.add').click(function(e) {
         e.preventDefault();
         grid.insertRow({});
-        newRow = $(grid.body.rows[collection.length - 1].$el);
+        var newRow = $(grid.body.rows[collection.length - 1].$el);
         newRow.attr("class", "new").click(function(e) {
           $(this).attr("class", "");
         });
+        $(newRow).pgMakeVisible('backform-tab');
         return false;
       });
 
@@ -1141,11 +1175,13 @@
             schema_node: schema_node,
             visible: (mode == 'properties'?
               (ver_in_limit ?
-               (s.version || true) : false) : s.version || true)
+               (s.version || true) : false) : s.version || true),
+            node: node,
+            node_data: treeData
           });
           delete o.id;
 
-          // Temporarily store in dictionaly format for
+          // Temporarily store in dictionary format for
           // utilizing it later.
           groups[group].push(o);
         }


reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected]
  Subject: Re: Variable control patch
  In-Reply-To: <CAFiP3vy4iZ_hiNhGJBYcZZnV-td=7K=hQLRgvKyrPHai0LSfzQ@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox