Resolved few intialization issue with Node model data, moved the

privileges functionality out of the backform.pgadmin.js to make it more
modular. Now - privileges will expect the privileges data in following
format:
<name_of_the_property> : [{
    "privileges": [{
        "privilege_type": <privilege_type>,
        "privilege": true,
        "with_grant": false
    },
    ...
    ],
    "grantee": <grantee>,
    "grantor": <grantor>
    },
   ...
]

Example:
acl": [{
    "privileges": [{
        "privilege_type": "CONNECT",
        "privilege": true,
        "with_grant": false
     	}],
    "grantee": '',
    "grantor": 'ashesh'
},{
    "privileges": [{
        "privilege_type": "CREATE",
        "privilege": true,
        "with_grant": false
    },{
        "privilege": true,
        "privilege_type": "TEMPORARY",
        "with_grant": false
    }],
    "grantee": test,
    "grantor": ashesh
}]
pull/3/head
Ashesh Vashi 2015-12-23 12:10:20 +05:30
parent bf5170bc89
commit c51ecc69e4
8 changed files with 575 additions and 308 deletions

View File

@ -8,7 +8,8 @@
##########################################################################
import json
from abc import ABCMeta, abstractmethod, abstractproperty
from flask import render_template, request, make_response, jsonify, current_app
from flask import render_template, request, make_response, jsonify, \
current_app, url_for
from flask.ext.security import login_required, current_user
from pgadmin.settings.settings_model import db, Server, ServerGroup, User
from pgadmin.utils.menu import MenuItem
@ -84,6 +85,25 @@ class ServerModule(sg.ServerGroupPluginModule):
return snippets
def get_own_javascripts(self):
scripts = []
scripts.extend([{
'name': 'pgadmin.node.server',
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load
},
{
'name': 'pgadmin.browser.server.privilege',
'path': url_for('browser.index') + 'server/static/js/privilege',
'when': self.node_type
}])
for module in self.submodules:
scripts.extend(module.get_own_javascripts())
return scripts
class ServerMenuItem(MenuItem):
def __init__(self, **kwargs):
@ -606,7 +626,8 @@ class ServerNode(PGChildNodeView):
),
'connected': True,
'type': manager.server_type,
'version': manager.version
'version': manager.version,
'db': manager.db
}
)

View File

@ -0,0 +1,431 @@
(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) {
/**
* Each Privilege, supporeted by an database object, will be represented
* using this Model.
*
* Defaults:
* privilege_type -> Name of the permission
* i.e. CREATE, TEMPORARY, CONNECT, etc.
* privilege -> Has privilege? (true/false)
* with_grant -> Has privilege with grant option (true/false)
**/
var PrivilegeModel = pgNode.Model.extend({
idAttribute: 'privilege_type',
defaults: {
privilege_type: undefined,
privilege: false,
with_grant: false
}
});
/**
* A database object has privileges item list (aclitem[]).
*
* This model represents the individual privilege item (aclitem).
* It has basically three properties:
* + grantee - Role to which that privilege applies to.
* Empty value represents to PUBLIC.
* + grantor - Granter who has given this permission.
* + privileges - Privileges for that role.
**/
var PrivilegeRoleModel = pgNode.PrivilegeRoleModel = pgNode.Model.extend({
defaults: {
grantee: undefined,
grantor: undefined,
privileges: undefined
},
/*
* Each of the database object needs to extend this model, which should
* provide the type of privileges (it supports).
*/
privileges:[],
schema: [{
id: 'grantee', label:'Grantee', type:'text', group: null, cell: 'string',
disabled: true, cellHeaderClasses: 'width_percent_40'
}, {
id: 'privileges', label:'Privileges',
type: 'collection', model: PrivilegeModel, group: null,
disabled: false, cell: 'privilege', control: 'text',
cellHeaderClasses: 'width_percent_40'
},{
id: 'grantor', label: 'Granter', type: 'text', disabled: true
}],
/*
* Initialize the model, which will transform the privileges string to
* collection of Privilege Model.
*/
initialize: function(attrs, opts) {
pgNode.Model.prototype.initialize.apply(this, arguments);
/*
* Define the collection of the privilege supported by this model
*/
var privileges = this.get('privileges') || {};
if (_.isArray(privileges)) {
privileges = new (pgNode.Collection)(
models, {
model: PrivilegeModel,
handler: this.handler || this,
silent: true,
parse: false
});
this.set('privileges', privileges, {silent: true});
}
var privs = {};
_.each(this.privileges, function(p) {
privs[p] = {
'privilige_type': p, 'privilege': false, 'with_grant': false
}
});
privileges.each(function(m) {
delete privs[m.get('privilege_type')];
});
_.each(privs, function(p) {
privileges.add(p, {silent: true});
});
return this;
},
toJSON: function(session) {
if (session) {
return pgNode.Model.prototype.apply(this, [true, false]);
}
var privileges = [];
this.attributes['privileges'].each(
function(p) {
if (p.get('privilege')) {
privileges.push(p.toJSON());
}
});
return {
'grantee': this.get('grantee'),
'grantor': this.get('grantor'),
'privileges': privileges
};
}
});
/**
Custom cell editor for editing privileges.
*/
var PrivilegeCellEditor = Backgrid.Extension.PrivilegeCellEditor =
Backgrid.CellEditor.extend({
tagName: "div",
// All available privileges in the PostgreSQL database server for
// generating the label for the specific Control
Labels: {
"C": "CREATE",
"T": "TEMP",
"c": "CONNECT",
"a": "INSERT",
"r": "SELECT",
"w": "UPDATE",
"d": "DELETE",
"D": "TRUNCATE",
"x": "REFERENCES",
"t": "TRIGGER",
"U": "USAGE",
"X": "EXECUTE"
},
template: _.template([
'<tr class="<%= header ? "header" : "" %>">',
' <td class="renderable">',
' <label>',
' <input type="checkbox" name="privilege" privilege="<%- privilege_type %>" target="<%- target %>" <%= privilege ? \'checked\' : "" %>></input>',
' <%- privilege_type %>',
' </label>',
' </td>',
' <td class="renderable">',
' <label>',
' <input type="checkbox" name="with_grant" privilege="<%- privilege_type %>" target="<%- target %>" <%= with_grant ? \'checked\' : "" %> <%= privilege ? "" : \'disabled\'%>></input>',
' WITH GRANT OPTION',
' </label>',
' </td>',
'</tr>'].join(" "), null, {variable: null}),
events: {
'change': 'privilegeChanged',
'blur': 'lostFocus'
},
render: function () {
this.$el.empty();
this.$el.attr('tabindex', '1');
this.$el.attr('target', this.elId);
var collection = this.model.get(this.column.get("name")),
tbl = $("<table></table>").appendTo(this.$el),
self = this,
privilege = true, with_grant = true;
// For each privilege generate html template.
// List down all the Privilege model.
collection.each(function(m) {
var d = m.toJSON();
_.extend(
d, {
'target': self.cid,
'header': false
});
privilege = (privilege && d.privilege);
with_grant = (with_grant && privilege && d.with_grant);
tbl.append(self.template(d));
});
// Preprend the ALL controls on that table
tbl.prepend(
self.template({
'target': self.cid,
'name': 'ALL',
'privilege_type': 'ALL',
'privilege': privilege,
'with_grant': with_grant,
'header': true
}));
self.$el.find('input[type=checkbox]').first().focus();
self.delegateEvents();
return this;
},
/*
* Listen to the checkbox value change and update the model accordingly.
*/
privilegeChanged: function(ev) {
if (ev && ev.target) {
/*
* We're looking for checkboxes only.
*/
var $el = $(ev.target),
privilege_type = $el.attr('privilege'),
type = $el.attr('name'),
checked = $el.prop('checked'),
$tr = $el.closest('tr'),
$tbl = $tr.closest('table'),
collection = this.model.get('privileges');;
/*
* If the checkbox selected/deselected is for 'ALL', we will select all
* the checkbox for each privilege.
*/
if (privilege_type == 'ALL') {
var $elGrant = $tr.find('input[name=with_grant]'),
$allPrivileges = $tbl.find(
'input[name=privilege][privilege!=\'ALL\']'
),
$allGrants = $tbl.find(
'input[name=with_grant][privilege!=\'ALL\']'
),
allPrivilege, allWithGrant;
if (type == 'privilege') {
/*
* We clicked the privilege checkbox, and not checkbox for with
* grant options.
*/
allPrivilege = checked;
allWithGrant = false;
if (checked) {
$allPrivileges.prop('checked', true);
/*
* We have clicked the ALL checkbox, we should be able to select
* the grant options too.
*/
$allGrants.prop('disabled', false);
$elGrant.prop('disabled', false);
} else {
/*
* ALL checkbox has been deselected, hence - we need to make
* sure.
* 1. Deselect all the privileges checkboxes
* 2. Deselect and disable all with grant privilege checkboxes.
* 3. Deselect and disable the checkbox for ALL with grant privilege.
*/
$allPrivileges.prop('checked', false);
$elGrant.prop('checked', false),
$allGrants.prop('checked', false);
$elGrant.prop('disabled', true);
$allGrants.prop('disabled', true);
}
} else {
/*
* We were able to click the ALL with grant privilege checkbox,
* that means, privilege for Privileges are true.
*
* We need to select/deselect all the with grant options
* checkboxes, based on the current value of the ALL with grant
* privilege checkbox.
*/
allPrivilege = true;
allWithGrant = checked;
$allGrants.prop('checked', checked);
}
/*
* Set the values for each Privilege Model.
*/
collection.each(function(m) {
m.set({'privilege': allPrivilege, 'with_grant': allWithGrant});
});
} else {
/*
* Particular privilege has been selected/deselected, which can be
* identified using the privilege="X" attribute.
*/
var attrs = {},
$tbl = $tr.closest('table'),
$allPrivilege = $tbl.find(
'input[name=privilege][privilege=\'ALL\']'
),
$allGrant = $tbl.find(
'input[name=with_grant][privilege=\'ALL\']'
);
attrs[type] = checked;
if (type == 'privilege') {
var $elGrant = ($el.closest('tr')).find('input[name=with_grant]');
if (!checked) {
attrs['with_grant'] = false;
$elGrant.prop('checked', false).prop('disabled', true);
$allPrivilege.prop('checked', false);
$allGrant.prop('disabled', true);
$allGrant.prop('checked', false);
} else {
$elGrant.prop('disabled', false);
}
} else if (!checked) {
$allGrant.prop('checked', false);
}
collection.get(privilege_type).set(attrs);
if (checked) {
var $allPrivileges = $tbl.find(
'input[name=privilege][privilege!=\'ALL\']:checked'
);
if ($allPrivileges.length == collection.models.length) {
$allPrivilege.prop('checked', true);
if (type == 'with_grant') {
var $allGrants = $tbl.find(
'input[name=with_grant][privilege!=\'ALL\']:checked'
);
if ($allGrants.length == collection.models.length) {
$allGrant.prop('disabled', false);
$allGrant.prop('checked', true);
}
} else {
$allGrant.prop('disabled', false);
}
}
}
}
}
},
lostFocus: function(ev) {
/*
* We lost the focuse, it's time for us to exit the editor.
*/
var m = this.model;
m.trigger('backgrid:edited', m, this.column, new Backgrid.Command(ev));
}
});
/*
* This will help us transform the privilieges value in proper format to be
* displayed in the cell.
*/
var PrivilegeCellFormatter = Backgrid.Extension.PrivilegeCellFormatter =
function () {};
_.extend(PrivilegeCellFormatter.prototype, {
notation: {
"CREATE" : "C",
"TEMPORARY" : "T",
"CONNECT" : "c",
"INSERT" : "a",
"SELECT" : "r",
"UPDATE" : "w",
"DELETE" : "d",
"TRUNCATE" : "D",
"REFERENCES" : "x",
"TRIGGER" : "t",
"USAGE" : "U",
"EXECUTE" : "X"
},
/**
* Takes a raw value from a model and returns an optionally formatted
* string for display.
*/
fromRaw: function (rawData, model) {
var res = '',
self = this;
if (rawData instanceof Backbone.Collection) {
rawData.each(function(m) {
if (m.get('privilege')) {
res += self.notation[m.get('privilege_type')];
if (m.get('with_grant')) {
res += '*';
}
}
});
}
return res;
}
});
/*
* PrivilegeCell for rendering and taking input for the privileges.
*/
var PrivilegeCell = Backgrid.Extension.PrivilegeCell = Backgrid.Cell.extend({
className: "edit-cell",
formatter: PrivilegeCellFormatter,
editor: PrivilegeCellEditor
});
return PrivilegeRoleModel;
}));

View File

@ -443,25 +443,44 @@ OWNER TO helpdesk;\n';
if (d) {
/* Loading all the scripts registered to be loaded on this node */
if (obj.scripts && obj.scripts[d._type]) {
_.each(obj.scripts[d._type], function(s) {
if (!s.loaded) {
require([s.name], function(m) {
s.loaded = true;
// Call the initialize (if present)
if (m && m.init && typeof m.init == 'function') {
try {
m.init();
} catch (err) {
obj.report_error(
'{{ _('Error Initializing script - ') }}' + s.path, err);
var scripts = _.extend({}, obj.scripts[d._type]);
/*
* We can remove it from the Browser.scripts object as
* these're about to be loaded.
*
* This will make sure that - we do check for the script for
* loading only once.
*
*/
delete obj.scripts[d._type];
setTimeout(function() {
_.each(scripts, function(s) {
if (!s.loaded) {
require([s.name], function(m) {
s.loaded = true;
// Call the initialize (if present)
if (m && m.init && typeof m.init == 'function') {
try {
m.init();
} catch (err) {
console.log("Error running module Init script for '" + s.path + "'");
console.log(err);
obj.report_error(
'{{ _('Error Initializing script - ') }}' + s.path, err);
}
}
}
}, function() {
obj.report_error(
'{{ _('Error loading script - ') }}' + s.path);
});
}
});
}, function() {
console.log("Error loading script - " + s.path);
console.log(arguments);
obj.report_error(
'{{ _('Error loading script - ') }}' + s.path);
}).bind(s);
}
});
}, 1);
}
}
break;

View File

@ -1005,7 +1005,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
Model: Backbone.Model.extend({
parse: function(res) {
var self = this;
if ('node' in res && res['node']) {
if (res && _.isObject(res) && 'node' in res && res['node']) {
self.tnode = _.extend({}, res.node);
delete res.node;
}
@ -1042,24 +1042,25 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
case 'model':
obj = self.get(s.id);
val = res[s.id];
if (_.isArray(val) || _.isObject(val)) {
if (!_.isObject(obj)) {
if (!_.isUndefined(val) && !_.isNull(val)) {
if (!obj || !(obj instanceof Backbone.Model)) {
if (_.isString(s.model) &&
s.model in pgBrowser.Nodes[s.model]) {
obj = new (pgBrowser.Nodes[s.model].Model)(
null, {handler: self.handler || self}
obj, {silent: true, handler: self.handler || self}
);
} else {
obj = new (s.model)(null, {handler: self.handler || self});
obj = new (s.model)(obj, {
silent: true, handler: self.handler || self
});
}
}
obj.set(self.get(s.id), {parse: true, silent: true});
obj.set(val, {parse: true, silent: true});
} else {
if (obj)
delete obj;
obj = null;
}
self.set(s.id, obj, {silent: true});
res[s.id] = obj;
break;
default:
@ -1072,6 +1073,8 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
initialize: function(attributes, options) {
var self = this;
Backbone.Model.prototype.initialize.apply(self, arguments);
if (_.isUndefined(options) || _.isNull(options)) {
options = attributes || {};
attributes = null;
@ -1088,31 +1091,35 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
if (self.schema && _.isArray(self.schema)) {
_.each(self.schema, function(s) {
var obj = null;
var obj = self.get(s.id);
switch(s.type) {
case 'collection':
if (_.isString(s.model) &&
if (!obj || !(obj instanceof pgBrowser.Node.Collection)) {
if (_.isString(s.model) &&
s.model in pgBrowser.Nodes) {
var node = pgBrowser.Nodes[s.model];
obj = new (node.Collection)(null, {
model: node.model,
handler: self.handler || self
});
} else {
obj = new (pgBrowser.Node.Collection)(null, {
model: s.model,
handler: self.handler || self
});
var node = pgBrowser.Nodes[s.model];
obj = new (node.Collection)(obj, {
model: node.model,
handler: self.handler || self
});
} else {
obj = new (pgBrowser.Node.Collection)(obj, {
model: s.model,
handler: self.handler || self
});
}
}
break;
case 'model':
if (_.isString(s.model) &&
s.model in pgBrowser.Nodes[s.model]) {
obj = new (pgBrowser.Nodes[s.model].Model)(
null, {handler: self.handler || self}
);
} else {
obj = new (s.model)(null, {handler: self.handler || self});
if (!obj || !(obj instanceof Backbone.Model)) {
if (_.isString(s.model) &&
s.model in pgBrowser.Nodes[s.model]) {
obj = new (pgBrowser.Nodes[s.model].Model)(
obj, {handler: self.handler || self}
);
} else {
obj = new (s.model)(obj, {handler: self.handler || self});
}
}
break;
default:
@ -1148,8 +1155,12 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
var self = this;
return (_.size(self.sessAttrs) > 0 ||
_.some(self.objects, function(o) {
return self.get(o).sessChanged();
_.some(self.objects, function(k) {
var obj = self.get(k);
if (!(_.isNull(obj) || _.isUndefined(obj))) {
return obj.sessChanged();
}
return false;
}));
},
sessValid: function() {
@ -1208,11 +1219,10 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
res = _.extend(res, self.sessAttrs);
}
_.each(self.objects, function(o) {
var obj = self.get(o);
if (session || obj)
res[o] = (obj && obj.toJSON(session));
});
_.each(self.objects, function(k) {
var obj = self.get(k);
res[k] = (obj && obj.toJSON(session));
});
return res;
},
startNewSession: function() {
@ -1229,6 +1239,10 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
_.each(self.objects, function(o) {
var obj = self.get(o);
if (_.isUndefined(obj) || _.isNull(obj)) {
return;
}
delete self.origSessAttrs[o];
if (obj && 'startNewSession' in obj && _.isFunction(obj.startNewSession)) {

View File

@ -57,6 +57,7 @@ class PGChildModule:
def __init__(self, *args, **kwargs):
self.min_ver = 1000000000
self.max_ver = 0
self.server_type = None
self.attributes = {}
super(PGChildModule, self).__init__(*args, **kwargs)

View File

@ -492,7 +492,11 @@ fieldset[disabled] .form-control {
}
.backgrid td.renderable:not(.editable):not(.delete-cell) {
background-color: #eee;
background-color: #F1F1F1;
}
.backgrid tr.header td.renderable:not(.editable):not(.delete-cell) {
background-color: #AAA;
}
.subnode-header {
@ -583,3 +587,11 @@ table.backgrid tr.new {
.switch-cell {
height: 0px; width: 0px;
}
.width_percent_40 {
width: 40%;
}
.width_percent_60 {
width: 60%;
}

View File

@ -36,7 +36,8 @@
var pgAdmin = (window.pgAdmin = window.pgAdmin || {});
pgAdmin.editableCell = function() {
if (this.attributes && this.attributes.disabled) {
if (this.attributes && !_.isUndefined(this.attributes.disabled) &&
!_.isNull(this.attributes.disabled)) {
if(_.isFunction(this.attributes.disabled)) {
return !(this.attributes.disabled.apply(this, arguments));
}
@ -503,14 +504,19 @@
initialize: function() {
Backform.Control.prototype.initialize.apply(this, arguments);
var uniqueCol = this.field.get('uniqueCol') || [];
var uniqueCol = this.field.get('uniqueCol') || [],
m = this.field.get('model'),
schema = m.prototype.schema || m.__super__.schema,
columns = [];
_.each(schema, function(s) {
columns.push(s.id);
});
var columns = this.field.get('columns')
// Check if unique columns provided are also in model attributes.
if (uniqueCol.length > _.intersection(columns, uniqueCol).length){
errorMsg = "Developer: Unique column/s [ "+_.difference(uniqueCol, columns)+" ] not found in collection model [ " + columns +" ]."
alert (errorMsg);
return null;
}
var collection = this.model.get(this.field.get('name')),
@ -747,7 +753,8 @@
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,
pgBrowser = window.pgAdmin.Browser;
// Set visibility of Add button
if (data.disabled || data.canAdd == false) {
@ -775,7 +782,17 @@
});
}
var collection = this.model.get(data.name);
var collection = self.model.get(data.name);
if (!collection) {
collection = new (pgBrowser.Node.Collection)(null, {
handler: self.model.handler || self,
model: data.model,
silent: true
});
self.model.set(data.name, collection, {silent: true});
}
// Initialize a new Grid instance
var grid = new Backgrid.Grid({
columns: gridSchema.columns,

View File

@ -119,254 +119,6 @@
}
});
/**
Custom cell formatter for privileges.
*/
var PrivilegeCellFormatter = Backgrid.Extension.PrivilegeCellFormatter = function () {};
_.extend(PrivilegeCellFormatter.prototype, {
fromRaw: function (rawData, model) {
return rawData;
},
/* Convert string privileges to object privileges for manipulation.
E.g C*Tc ===> {"C":{"privilege":true,
"withGrantPrivilege":true},
"T":{"privilege":true,
"withGrantPrivilege":false},
"c":{"privilege":true,
"withGrantPrivilege":false}
}
*/
fromRawToObject: function (rawData, model) {
var objData = {};
var currentChar = "";
for (var i = 0, len = rawData.length; i < len; i++) {
if (rawData[i] == "*" && currentChar != ""){
if ( _.has(objData,currentChar)){
objData[currentChar]["withGrantPrivilege"] = true;
}
}else{
currentChar = rawData[i]
objData[currentChar] = {"privilege":true,
"withGrantPrivilege":false};
}
}
return objData;
},
toRaw: function (formattedData, model) {
return formattedData;
}
});
/**
Custom cell editor for editing privileges.
*/
var PrivilegeCellEditor = Backgrid.Extension.PrivilegeCellEditor = Backgrid.CellEditor.extend({
tagName: "div",
template: _.template(['<tr>',
'<td class="renderable"><label><input type="checkbox" name="<%- value %>" <%= privilege ? \'checked\' : "" %>><%- name %></label></td>',
'<td class="renderable"><label><input type="checkbox" name="<%- value %>_grant" <%= withGrantPrivilege ? \'checked\' : "" %>>WITH GRANT OPTION</label></td>',
'</tr>'].join(" "), null, {variable: null}),
initialize: function() {
Backgrid.CellEditor.prototype.initialize.apply(this, arguments);
this.elId = _.uniqueId('pgPriv_');
},
setPrivilegeOptions: function (privilegeOptions){
this.privilegeOptions = privilegeOptions;
},
render: function () {
this.$el.empty();
this.$el.attr('tabindex', '1');
this.$el.attr('id', this.elId);
this.$el.attr('privilegeseditor', '1');
var privilegeOptions = _.result(this, "privilegeOptions");
var model = this.model;
var selectedValues = this.formatter.fromRawToObject(model.get(this.column.get("name")), model),
tbl = $("<table></table>").appendTo(this.$el);
if (!_.isArray(privilegeOptions)) throw new TypeError("privilegeOptions must be an array");
self = this;
// For each privilege generate html template.
_.each(privilegeOptions, function (privilegeOption){
var templateData = {name: privilegeOption['name'],
value: privilegeOption['value'],
privilege : false,
withGrantPrivilege : false
};
if ( _.has(selectedValues,privilegeOption['value'])){
_.extend(templateData,{ privilege:selectedValues[privilegeOption['value']]["privilege"],
withGrantPrivilege:selectedValues[privilegeOption['value']]["withGrantPrivilege"]
});
}
var editorHtml = self.template(templateData);
tbl.append(editorHtml);
var $prvilegeGrantCheckbox = self.$el.find("[name='" + privilegeOption['value'] + "_grant']");
// Add event listeners on each privilege checkbox. And set initial state.
// Update model if user changes value.
$prvilegeGrantCheckbox.click(function(e) {
var addRemoveflag = $(this).is(':checked');
privilege = this.name;
self.updateModel(privilege, addRemoveflag);
});
var $prvilegeCheckbox = self.$el.find("[name='" + privilegeOption['value'] + "']");
if (!$prvilegeCheckbox.is(':checked')) {
$prvilegeGrantCheckbox.attr("disabled", true);
$prvilegeGrantCheckbox.attr("checked", false);
}
$prvilegeCheckbox.click(function(e) {
var addRemoveflag = $(this).is(':checked');
privilege = this.name;
if (addRemoveflag) {
$prvilegeGrantCheckbox.removeAttr("disabled");
} else {
$prvilegeGrantCheckbox.attr("disabled", true);
$prvilegeGrantCheckbox.attr("checked", false);
}
self.updateModel(privilege, addRemoveflag);
});
});
self.$el.find('input[type=checkbox]').blur(self.focusLost.bind(this)).first().focus();
self.delegateEvents();
return this;
},
updateModel: function(privilege, addRemoveflag){
// Update model with new privilege string. e.g. 'C*Tc'.
var self = this,
model = self.model,
column = self.column,
newVal = "",
withGrant = false,
privilegeConst = privilege[0];
if (privilege.length > 1){
withGrant = true;
}
oldValObj = self.formatter.fromRawToObject(model.get(self.column.get("name")), model);
if (addRemoveflag){
if (!withGrant){
oldValObj[privilegeConst] = {"privilege": true,
"withGrantPrivilege":false};
}else{
oldValObj[privilegeConst] = {"privilege": true,
"withGrantPrivilege":true}
}
}else{
if (!withGrant){
oldValObj[privilegeConst] = {"privilege": false,
"withGrantPrivilege":false};
}else{
oldValObj[privilegeConst] = {"privilege": true,
"withGrantPrivilege":false};
}
}
for (var i = 0, len = model.privileges.length; i < len; i++) {
if ( _.has(oldValObj, model.privileges[i])){
if(oldValObj[model.privileges[i]]["privilege"]){
newVal = newVal + model.privileges[i]
}
if(oldValObj[model.privileges[i]]["withGrantPrivilege"]){
newVal = newVal + "*"
}
}
}
model.set(column.get("name"), newVal);
},
focusLost :function(e) {
setTimeout(
function() {
var lostFocus = true;
if (document.activeElement) {
lostFocus = !(
$(document.activeElement).closest(
'div[privilegeseditor=1]'
).first().attr('id') == this.$el.attr('id')
);
}
if (lostFocus) {
this.model.trigger("backgrid:edited", this.model, this.column, new Backgrid.Command(e));
}
}.bind(this), 200);
}
});
var PrivilegeCell = Backgrid.Extension.PrivilegeCell = Backgrid.Cell.extend({
className: "edit-cell",
// All available privileges.
privilegeLabels: { "C": "CREATE",
"T": "TEMP",
"c": "CONNECT",
"a": "INSERT",
"r": "SELECT",
"w": "UPDATE",
"d": "DELETE",
"D": "TRUNCATE",
"x": "REFERENCES",
"t": "TRIGGER",
"U": "USAGE",
"X": "EXECUTE"
},
formatter: PrivilegeCellFormatter,
editor: PrivilegeCellEditor,
initialize: function(options) {
Backgrid.Cell.prototype.initialize.apply(this, arguments);
var privilegeOptions = [];
var privileges = this.model.privileges || [];
self = this;
// Generate array of privileges to be shown in editor.
_.each(privileges, function(privilege){
privilegeOptions.push({name:self.privilegeLabels[privilege],
value:privilege})
})
this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
if (column.get("name") == this.column.get("name"))
// Set available privilege options in editor.
editor.setPrivilegeOptions(privilegeOptions);
});
},
render: function(){
this.$el.empty();
var model = this.model;
this.$el.text(this.formatter.fromRaw(model.get(this.column.get("name")), model));
this.delegateEvents();
if (this.grabFocus)
this.$el.focus();
return this;
},
exitEditMode: function() {
Backgrid.Cell.prototype.exitEditMode.apply(this, arguments);
this.render();
}
});
var ObjectCell = Backgrid.Extension.ObjectCell = Backgrid.Cell.extend({
editorOptionDefaults: {
schema: []