diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 56b9c3c20..3ae4fc036 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -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 } ) diff --git a/web/pgadmin/browser/server_groups/servers/static/js/privilege.js b/web/pgadmin/browser/server_groups/servers/static/js/privilege.js new file mode 100644 index 000000000..190183e2f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/static/js/privilege.js @@ -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([ + '">', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ''].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 = $("
").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; +})); diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js index 93d30c0db..f44b7db96 100644 --- a/web/pgadmin/browser/templates/browser/js/browser.js +++ b/web/pgadmin/browser/templates/browser/js/browser.js @@ -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; diff --git a/web/pgadmin/browser/templates/browser/js/node.js b/web/pgadmin/browser/templates/browser/js/node.js index e097525ca..afcabf1b2 100644 --- a/web/pgadmin/browser/templates/browser/js/node.js +++ b/web/pgadmin/browser/templates/browser/js/node.js @@ -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)) { diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py index 665bade23..590493e6a 100644 --- a/web/pgadmin/browser/utils.py +++ b/web/pgadmin/browser/utils.py @@ -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) diff --git a/web/pgadmin/static/css/overrides.css b/web/pgadmin/static/css/overrides.css index df5f3301b..04b22245d 100644 --- a/web/pgadmin/static/css/overrides.css +++ b/web/pgadmin/static/css/overrides.css @@ -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%; +} diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index 23dec7e1e..f8e3ca160 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -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, diff --git a/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js index 74f769062..b12c089c3 100644 --- a/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js +++ b/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js @@ -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(['', - '', - '', - ''].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 = $("
").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: []