2019-01-02 04:24:12 -06:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
|
|
//
|
|
|
|
// Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
|
|
|
// This software is released under the PostgreSQL Licence
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
2016-09-22 09:27:59 -05:00
|
|
|
define([
|
2017-08-08 22:02:16 -05:00
|
|
|
'sources/gettext', 'jquery', 'underscore', 'sources/pgadmin', 'backbone', 'backform',
|
2018-01-12 01:29:51 -06:00
|
|
|
'alertify', 'backgrid', 'select2', 'pgadmin.browser.node',
|
|
|
|
], function(gettext, $, _, pgAdmin, Backbone, Backform, Alertify, Backgrid) {
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2016-09-22 09:27:59 -05:00
|
|
|
/*
|
|
|
|
* Define the selectAll adapter for select2.
|
|
|
|
*
|
|
|
|
* Reference:
|
|
|
|
* https://github.com/select2/select2/issues/195#issuecomment-240130634
|
|
|
|
*/
|
|
|
|
$.fn.select2.amd.define('select2/selectAllAdapter', [
|
|
|
|
'select2/utils',
|
|
|
|
'select2/dropdown',
|
2018-01-12 01:29:51 -06:00
|
|
|
'select2/dropdown/attachBody',
|
|
|
|
], function(Utils, Dropdown, AttachBody) {
|
2016-09-22 09:27:59 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
function SelectAll() {}
|
|
|
|
SelectAll.prototype.render = function(decorated) {
|
2018-08-22 04:43:40 -05:00
|
|
|
let self = this;
|
|
|
|
let $rendered = decorated.call(this);
|
|
|
|
|
|
|
|
let $selectAll = $([
|
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
|
|
|
'<button class="btn btn-secondary btn-sm" type="button"',
|
2018-08-22 04:43:40 -05:00
|
|
|
' style="width: 49%;margin: 0 0.5%;">',
|
|
|
|
'<i class="fa fa-check-square-o"></i>',
|
|
|
|
'<span style="padding: 0px 5px;">',
|
|
|
|
gettext('Select All'),
|
|
|
|
'</span></button>',
|
|
|
|
].join(''));
|
|
|
|
|
|
|
|
let $unselectAll = $([
|
Improvement in the look and feel of the whole application
Changed the SCSS/CSS for the below third party libraries to adopt the
new look 'n' feel:
- wcDocker
- Alertify dialogs, and notifications
- AciTree
- Bootstrap Navbar
- Bootstrap Tabs
- Bootstrap Drop-Down menu
- Backgrid
- Select2
Adopated the new the look 'n' feel for the dialogs, wizard, properties,
tab panels, tabs, fieldset, subnode control, spinner control, HTML
table, and other form controls.
- Font is changed to Roboto
- Using SCSS variables to define the look 'n' feel
- Designer background images for the Login, and Forget password pages in
'web' mode
- Improved the look 'n' feel for the key selection in the preferences
dialog
- Table classes consistency changes across the application
- File Open and Save dialog list view changes
Author(s): Aditya Toshniwal & Khushboo Vashi
2018-12-21 05:44:55 -06:00
|
|
|
'<button class="btn btn-secondary btn-sm" type="button"',
|
2018-08-22 04:43:40 -05:00
|
|
|
' style="width: 49%;margin: 0 0.5%;">',
|
|
|
|
'<i class="fa fa-square-o"></i><span style="padding: 0px 5px;">',
|
|
|
|
gettext('Unselect All'),
|
|
|
|
'</span></button>',
|
|
|
|
].join(''));
|
|
|
|
|
|
|
|
let $btnContainer = $(
|
2018-10-09 05:22:54 -05:00
|
|
|
'<div class="select2-select-all-adapter-container">'
|
2018-08-22 04:43:40 -05:00
|
|
|
).append($selectAll).append($unselectAll);
|
2016-09-22 09:27:59 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (!this.$element.prop('multiple')) {
|
2016-09-22 09:27:59 -05:00
|
|
|
// this isn't a multi-select -> don't add the buttons!
|
|
|
|
return $rendered;
|
|
|
|
}
|
|
|
|
$rendered.find('.select2-dropdown').prepend($btnContainer);
|
2018-08-22 04:43:40 -05:00
|
|
|
// Select All button click
|
2018-01-12 01:29:51 -06:00
|
|
|
$selectAll.on('click', function() {
|
|
|
|
$rendered.find('.select2-results__option[aria-selected=false]').each(
|
|
|
|
function() {
|
2018-08-22 04:43:40 -05:00
|
|
|
// Note: With latest version we do not get data in the data attribute of a element
|
|
|
|
// Hence as per new logic we will fetch the data from the cache created by Select2.
|
|
|
|
let data = Utils.GetData($(this)[0], 'data');
|
2018-01-12 01:29:51 -06:00
|
|
|
self.trigger('select', {
|
2018-08-22 04:43:40 -05:00
|
|
|
data: data,
|
2018-01-12 01:29:51 -06:00
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
2016-09-22 09:27:59 -05:00
|
|
|
self.trigger('close');
|
|
|
|
});
|
2018-08-22 04:43:40 -05:00
|
|
|
// Unselect All button click
|
2018-01-12 01:29:51 -06:00
|
|
|
$unselectAll.on('click', function() {
|
|
|
|
$rendered.find('.select2-results__option[aria-selected=true]').each(
|
|
|
|
function() {
|
2018-08-22 04:43:40 -05:00
|
|
|
let data = Utils.GetData($(this)[0], 'data');
|
2018-01-12 01:29:51 -06:00
|
|
|
self.trigger('unselect', {
|
2018-08-22 04:43:40 -05:00
|
|
|
data: data,
|
2018-01-12 01:29:51 -06:00
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
2016-09-22 09:27:59 -05:00
|
|
|
self.trigger('close');
|
|
|
|
});
|
|
|
|
return $rendered;
|
|
|
|
};
|
|
|
|
|
|
|
|
return Utils.Decorate(
|
|
|
|
Utils.Decorate(
|
|
|
|
Dropdown,
|
|
|
|
AttachBody
|
|
|
|
),
|
|
|
|
SelectAll
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2015-12-27 13:30:20 -06:00
|
|
|
/*
|
|
|
|
* NodeAjaxOptionsControl
|
|
|
|
* This control will fetch the options required to render the select
|
|
|
|
* control, from the url specific to the pgAdmin.Browser node object.
|
|
|
|
*
|
|
|
|
* In order to use this properly, schema require to set the 'url' property,
|
|
|
|
* which exposes the data for this node.
|
|
|
|
*
|
|
|
|
* In case the url is not providing the data in proper format, we can
|
|
|
|
* specify the 'transform' function too, which will convert the fetched
|
|
|
|
* data to proper 'label', 'value' format.
|
|
|
|
*/
|
|
|
|
var NodeAjaxOptionsControl = Backform.NodeAjaxOptionsControl =
|
2018-01-12 01:29:51 -06:00
|
|
|
Backform.Select2Control.extend({
|
|
|
|
defaults: _.extend(Backform.Select2Control.prototype.defaults, {
|
|
|
|
url: undefined,
|
|
|
|
transform: undefined,
|
|
|
|
url_with_id: false,
|
|
|
|
select2: {
|
|
|
|
allowClear: true,
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2018-01-12 01:29:51 -06:00
|
|
|
width: 'style',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
initialize: function() {
|
|
|
|
/*
|
|
|
|
* Initialization from the original control.
|
|
|
|
*/
|
|
|
|
Backform.Select2Control.prototype.initialize.apply(this, arguments);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're about to fetch the options required for this control.
|
|
|
|
*/
|
|
|
|
var self = this,
|
2015-12-27 13:30:20 -06:00
|
|
|
url = self.field.get('url') || self.defaults.url,
|
2016-01-15 05:17:17 -06:00
|
|
|
m = self.model.top || self.model;
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
// Hmm - we found the url option.
|
|
|
|
// That means - we needs to fetch the options from that node.
|
|
|
|
if (url) {
|
|
|
|
var node = this.field.get('schema_node'),
|
2016-01-05 03:06:30 -06:00
|
|
|
node_info = this.field.get('node_info'),
|
2016-04-29 05:11:24 -05:00
|
|
|
with_id = this.field.get('url_with_id') || false,
|
2015-12-27 13:30:20 -06:00
|
|
|
full_url = node.generate_url.apply(
|
|
|
|
node, [
|
2018-01-12 01:29:51 -06:00
|
|
|
null, url, this.field.get('node_data'), with_id, node_info,
|
2015-12-27 13:30:20 -06:00
|
|
|
]),
|
2016-04-29 05:11:24 -05:00
|
|
|
cache_level,
|
2016-01-09 06:29:56 -06:00
|
|
|
cache_node = this.field.get('cache_node');
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
cache_node = (cache_node && pgAdmin.Browser.Nodes[cache_node]) || node;
|
2016-01-09 06:29:56 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (this.field.has('cache_level')) {
|
|
|
|
cache_level = this.field.get('cache_level');
|
|
|
|
} else {
|
|
|
|
cache_level = cache_node.cache_level(node_info, with_id);
|
|
|
|
}
|
2016-04-29 05:11:24 -05:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
/*
|
|
|
|
* We needs to check, if we have already cached data for this url.
|
|
|
|
* If yes - use that, and do not bother about fetching it again,
|
|
|
|
* and use it.
|
|
|
|
*/
|
|
|
|
var data = cache_node.cache(node.type + '#' + url, node_info, cache_level);
|
2016-01-09 06:29:56 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (this.field.get('version_compatible') &&
|
2016-01-12 00:31:45 -06:00
|
|
|
(_.isUndefined(data) || _.isNull(data))) {
|
2018-01-12 01:29:51 -06:00
|
|
|
m.trigger('pgadmin:view:fetching', m, self.field);
|
|
|
|
$.ajax({
|
|
|
|
async: false,
|
|
|
|
url: full_url,
|
2018-07-09 07:54:00 -05:00
|
|
|
})
|
|
|
|
.done(function(res) {
|
|
|
|
/*
|
|
|
|
* We will cache this data for short period of time for avoiding
|
|
|
|
* same calls.
|
|
|
|
*/
|
|
|
|
data = cache_node.cache(node.type + '#' + url, node_info, cache_level, res.data);
|
|
|
|
})
|
|
|
|
.fail(function() {
|
|
|
|
m.trigger('pgadmin:view:fetch:error', m, self.field);
|
2018-01-12 01:29:51 -06:00
|
|
|
});
|
|
|
|
m.trigger('pgadmin:view:fetched', m, self.field);
|
|
|
|
}
|
|
|
|
// To fetch only options from cache, we do not need time from 'at'
|
|
|
|
// attribute but only options.
|
|
|
|
//
|
|
|
|
// It is feasible that the data may not have been fetched.
|
|
|
|
data = (data && data.data) || [];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transform the data
|
|
|
|
*/
|
|
|
|
var transform = this.field.get('transform') || self.defaults.transform;
|
|
|
|
if (transform && _.isFunction(transform)) {
|
|
|
|
// We will transform the data later, when rendering.
|
|
|
|
// It will allow us to generate different data based on the
|
|
|
|
// dependencies.
|
|
|
|
self.field.set('options', transform.bind(self, data));
|
|
|
|
} else {
|
|
|
|
self.field.set('options', data);
|
|
|
|
}
|
2015-12-27 13:30:20 -06:00
|
|
|
}
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
|
|
|
});
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2016-01-09 06:29:56 -06:00
|
|
|
var formatNode = function(opt) {
|
|
|
|
if (!opt.id) {
|
|
|
|
return opt.text;
|
|
|
|
}
|
|
|
|
|
|
|
|
var optimage = $(opt.element).data('image');
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (!optimage) {
|
2016-01-09 06:29:56 -06:00
|
|
|
return opt.text;
|
|
|
|
} else {
|
Improvised the 'transform/options' function usage with the Select2Cell.
The current implementaton binds the cell/control object, and the ajax
data in the asychronous Cells/Controls with the 'options' functions
extended from the Select2Cell.
The problem starts when we try to fetch the current model from that
options/transform/filter function to do some operation, which does not
require in most of the cases. Except the privileges control - where we
needed the current model for omitting the existing selected object
during transformation, and filtering.
In order resolved the issue, we need a common object, which is shared
among the Cell. In backgrid, the 'Column' object is mong the cell,
hence - implementation logic has been changed to bid the 'Column' object
with the 'options' function and, passed the 'Cell' object as an
arguments.
Because - we do use the common function 'transform' between 'Control'
and 'Cell', we needed make changes in the Select2Control to pass the
Control object as an arguments.
And, make the changes in the privileges control to use the new
implementation. The same logic is also required in some of the
operations, we will be/are working on the table/column nodes.
2016-04-08 00:30:48 -05:00
|
|
|
return $('<span></span>').append(
|
2018-01-12 01:29:51 -06:00
|
|
|
$('<span></span>', {
|
|
|
|
class: 'wcTabIcon ' + optimage,
|
|
|
|
})
|
|
|
|
).append($('<span></span>').text(opt.text));
|
2016-01-09 06:29:56 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-27 13:30:20 -06:00
|
|
|
var NodeListByIdControl = Backform.NodeListByIdControl = NodeAjaxOptionsControl.extend({
|
|
|
|
controlClassName: 'pgadmin-node-select form-control',
|
2016-01-15 06:55:13 -06:00
|
|
|
defaults: _.extend({}, NodeAjaxOptionsControl.prototype.defaults, {
|
2015-12-27 13:30:20 -06:00
|
|
|
url: 'nodes',
|
2016-01-04 01:13:24 -06:00
|
|
|
filter: undefined,
|
2015-12-27 13:30:20 -06:00
|
|
|
transform: function(rows) {
|
|
|
|
var self = this,
|
2018-01-12 01:29:51 -06:00
|
|
|
node = self.field.get('schema_node'),
|
|
|
|
res = [],
|
|
|
|
filter = self.field.get('filter') || function() {
|
|
|
|
return true;
|
|
|
|
};
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2016-01-05 14:55:13 -06:00
|
|
|
filter = filter.bind(self);
|
|
|
|
|
2015-12-27 13:30:20 -06:00
|
|
|
_.each(rows, function(r) {
|
2016-01-04 01:13:24 -06:00
|
|
|
if (filter(r)) {
|
|
|
|
var l = (_.isFunction(node['node_label']) ?
|
2018-01-12 01:29:51 -06:00
|
|
|
(node['node_label']).apply(node, [r, self.model, self]) :
|
|
|
|
r.label),
|
|
|
|
image = (_.isFunction(node['node_image']) ?
|
|
|
|
(node['node_image']).apply(
|
|
|
|
node, [r, self.model, self]
|
|
|
|
) :
|
|
|
|
(node['node_image'] || ('icon-' + node.type)));
|
2016-01-09 06:29:56 -06:00
|
|
|
|
2016-01-04 01:13:24 -06:00
|
|
|
res.push({
|
|
|
|
'value': r._id,
|
2016-01-09 06:29:56 -06:00
|
|
|
'image': image,
|
2018-01-12 01:29:51 -06:00
|
|
|
'label': l,
|
2016-01-04 01:13:24 -06:00
|
|
|
});
|
|
|
|
}
|
2015-12-27 13:30:20 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
2016-01-09 06:29:56 -06:00
|
|
|
},
|
|
|
|
select2: {
|
|
|
|
allowClear: true,
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2016-01-09 06:29:56 -06:00
|
|
|
width: 'style',
|
|
|
|
templateResult: formatNode,
|
2018-01-12 01:29:51 -06:00
|
|
|
templateSelection: formatNode,
|
|
|
|
},
|
|
|
|
}),
|
2015-12-27 13:30:20 -06:00
|
|
|
});
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
Backform.NodeListByNameControl = NodeListByIdControl.extend({
|
2016-01-15 06:55:13 -06:00
|
|
|
defaults: _.extend({}, NodeListByIdControl.prototype.defaults, {
|
2015-12-27 13:30:20 -06:00
|
|
|
transform: function(rows) {
|
|
|
|
var self = this,
|
2018-01-12 01:29:51 -06:00
|
|
|
node = self.field.get('schema_node'),
|
|
|
|
res = [],
|
|
|
|
filter = self.field.get('filter') || function() {
|
|
|
|
return true;
|
|
|
|
};
|
2015-12-27 13:30:20 -06:00
|
|
|
|
2016-01-05 14:55:13 -06:00
|
|
|
filter = filter.bind(self);
|
|
|
|
|
2015-12-27 13:30:20 -06:00
|
|
|
_.each(rows, function(r) {
|
2016-01-04 01:13:24 -06:00
|
|
|
if (filter(r)) {
|
|
|
|
var l = (_.isFunction(node['node_label']) ?
|
2018-01-12 01:29:51 -06:00
|
|
|
(node['node_label']).apply(node, [r, self.model, self]) :
|
|
|
|
r.label),
|
|
|
|
image = (_.isFunction(node['node_image']) ?
|
|
|
|
(node['node_image']).apply(
|
|
|
|
node, [r, self.model, self]
|
|
|
|
) :
|
|
|
|
(node['node_image'] || ('icon-' + node.type)));
|
2016-01-04 01:13:24 -06:00
|
|
|
res.push({
|
2016-01-05 14:55:13 -06:00
|
|
|
'value': r.label,
|
2016-01-09 06:29:56 -06:00
|
|
|
'image': image,
|
2018-01-12 01:29:51 -06:00
|
|
|
'label': l,
|
2016-01-04 01:13:24 -06:00
|
|
|
});
|
|
|
|
}
|
2015-12-27 13:30:20 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
|
|
|
}),
|
2015-12-27 13:30:20 -06:00
|
|
|
});
|
|
|
|
|
2016-01-09 06:29:56 -06:00
|
|
|
/*
|
|
|
|
* Global function to make visible particular dom element in it's parent
|
|
|
|
* with given class.
|
|
|
|
*/
|
2018-01-12 01:29:51 -06:00
|
|
|
$.fn.pgMakeVisible = function(cls) {
|
2016-01-09 06:29:56 -06:00
|
|
|
return this.each(function() {
|
|
|
|
if (!this || !$(this.length))
|
|
|
|
return;
|
2018-01-12 01:29:51 -06:00
|
|
|
var top, p = $(this),
|
|
|
|
hasScrollbar = function(j) {
|
|
|
|
if (j && j.length > 0) {
|
|
|
|
return j.get(0).scrollHeight > j.height();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
2016-01-09 06:29:56 -06:00
|
|
|
|
2016-04-13 10:11:43 -05:00
|
|
|
// check if p is not empty
|
2018-01-12 01:29:51 -06:00
|
|
|
while (p && p.length > 0) {
|
2016-01-09 06:29:56 -06:00
|
|
|
top = p.get(0).offsetTop + p.height();
|
|
|
|
p = p.parent();
|
|
|
|
if (hasScrollbar(p)) {
|
|
|
|
p.scrollTop(top);
|
|
|
|
}
|
|
|
|
if (p.hasClass(cls)) //'backform-tab'
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-15 06:55:13 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* NodeAjaxOptionsCell
|
|
|
|
* This cell will fetch the options required to render the select
|
|
|
|
* cell, from the url specific to the pgAdmin.Browser node object.
|
|
|
|
*
|
|
|
|
* In order to use this properly, schema require to set the 'url' property,
|
|
|
|
* which exposes the data for this node.
|
|
|
|
*
|
|
|
|
* In case the url is not providing the data in proper format, we can
|
|
|
|
* specify the 'transform' function too, which will convert the fetched
|
|
|
|
* data to proper 'label', 'value' format.
|
|
|
|
*/
|
|
|
|
var NodeAjaxOptionsCell = Backgrid.Extension.NodeAjaxOptionsCell = Backgrid.Extension.Select2Cell.extend({
|
|
|
|
defaults: _.extend({}, Backgrid.Extension.Select2Cell.prototype.defaults, {
|
|
|
|
url: undefined,
|
|
|
|
transform: undefined,
|
|
|
|
url_with_id: false,
|
|
|
|
select2: {
|
|
|
|
allowClear: true,
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2018-01-12 01:29:51 -06:00
|
|
|
width: 'style',
|
Improvised Select2Cell, and SwitchCell.
Removed the use of separate editor for both of these cell types. There
were two instance of select2 were getting created in the Select2Cell,
one in the Select2Cell itself, and another in Select2CellEditor. And,
loosing the focus mysteriously, and making the scrollbar in the property
dialog non-responsive.
Also, modified the NodeAjaxOptionsCell to use the above logic, and
removed its own version of render function to make it consitent across
the system.
This patch [changes sent by Murtuza] also includes improvisation in the
DeleteCell, and ObjectCell, which will honour now 'canRemoveRow', and
''canEditRow' respective properties of Column.
2016-04-12 06:20:43 -05:00
|
|
|
},
|
|
|
|
opt: {
|
|
|
|
label: null,
|
|
|
|
value: null,
|
|
|
|
image: null,
|
2018-01-12 01:29:51 -06:00
|
|
|
selected: false,
|
|
|
|
},
|
2016-01-15 06:55:13 -06:00
|
|
|
}),
|
|
|
|
template: _.template(
|
Improvised Select2Cell, and SwitchCell.
Removed the use of separate editor for both of these cell types. There
were two instance of select2 were getting created in the Select2Cell,
one in the Select2Cell itself, and another in Select2CellEditor. And,
loosing the focus mysteriously, and making the scrollbar in the property
dialog non-responsive.
Also, modified the NodeAjaxOptionsCell to use the above logic, and
removed its own version of render function to make it consitent across
the system.
This patch [changes sent by Murtuza] also includes improvisation in the
DeleteCell, and ObjectCell, which will honour now 'canRemoveRow', and
''canEditRow' respective properties of Column.
2016-04-12 06:20:43 -05:00
|
|
|
'<option <% if (image) { %> data-image=<%= image %> <% } %> value="<%- value %>" <%= selected ? \'selected="selected"\' : "" %>><%- label %></option>'
|
2016-01-15 06:55:13 -06:00
|
|
|
),
|
2018-01-12 01:29:51 -06:00
|
|
|
initialize: function() {
|
2016-01-15 06:55:13 -06:00
|
|
|
Backgrid.Extension.Select2Cell.prototype.initialize.apply(this, arguments);
|
|
|
|
|
2016-03-15 08:28:16 -05:00
|
|
|
var url = this.column.get('url') || this.defaults.url,
|
2018-01-12 01:29:51 -06:00
|
|
|
is_options_cached = _.has(this.column.attributes, 'options_cached'),
|
|
|
|
options_cached = is_options_cached && this.column.get('options_cached');
|
2016-01-15 06:55:13 -06:00
|
|
|
// Hmm - we found the url option.
|
|
|
|
// That means - we needs to fetch the options from that node.
|
2016-03-15 08:28:16 -05:00
|
|
|
if (url && !options_cached) {
|
|
|
|
|
|
|
|
var self = this,
|
2018-01-12 01:29:51 -06:00
|
|
|
m = this.model,
|
|
|
|
column = this.column,
|
|
|
|
eventHandler = m.top || m,
|
|
|
|
node = column.get('schema_node'),
|
|
|
|
node_info = column.get('node_info'),
|
|
|
|
with_id = column.get('url_with_id') || false,
|
|
|
|
full_url = node.generate_url.apply(
|
|
|
|
node, [
|
|
|
|
null, url, column.get('node_data'), with_id, node_info,
|
|
|
|
]),
|
|
|
|
cache_level,
|
|
|
|
cache_node = column.get('cache_node');
|
2016-01-15 06:55:13 -06:00
|
|
|
|
2017-12-13 09:17:17 -06:00
|
|
|
cache_node = (cache_node && pgAdmin.Browser.Nodes[cache_node]) || node;
|
2016-01-15 06:55:13 -06:00
|
|
|
|
2016-04-29 06:55:16 -05:00
|
|
|
if (column.has('cache_level')) {
|
|
|
|
cache_level = column.get('cache_level');
|
2016-04-29 05:11:24 -05:00
|
|
|
} else {
|
|
|
|
cache_level = cache_node.cache_level(node_info, with_id);
|
|
|
|
}
|
|
|
|
|
2016-01-15 06:55:13 -06:00
|
|
|
/*
|
|
|
|
* We needs to check, if we have already cached data for this url.
|
|
|
|
* If yes - use that, and do not bother about fetching it again,
|
|
|
|
* and use it.
|
|
|
|
*/
|
2016-04-29 05:11:24 -05:00
|
|
|
var data = cache_node.cache(node.type + '#' + url, node_info, cache_level);
|
2016-01-15 06:55:13 -06:00
|
|
|
|
2016-03-15 08:28:16 -05:00
|
|
|
if (column.get('version_compatible') &&
|
2018-01-12 01:29:51 -06:00
|
|
|
(_.isUndefined(data) || _.isNull(data))) {
|
2016-03-15 08:28:16 -05:00
|
|
|
eventHandler.trigger('pgadmin:view:fetching', m, column);
|
2016-01-15 06:55:13 -06:00
|
|
|
$.ajax({
|
|
|
|
async: false,
|
|
|
|
url: full_url,
|
2018-07-09 07:54:00 -05:00
|
|
|
})
|
|
|
|
.done(function(res) {
|
|
|
|
/*
|
|
|
|
* We will cache this data for short period of time for avoiding
|
|
|
|
* same calls.
|
|
|
|
*/
|
|
|
|
data = cache_node.cache(node.type + '#' + url, node_info, cache_level, res.data);
|
|
|
|
})
|
|
|
|
.fail(function() {
|
|
|
|
eventHandler.trigger('pgadmin:view:fetch:error', m, column);
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
2016-03-15 08:28:16 -05:00
|
|
|
eventHandler.trigger('pgadmin:view:fetched', m, column);
|
2016-01-15 06:55:13 -06:00
|
|
|
}
|
|
|
|
// To fetch only options from cache, we do not need time from 'at'
|
|
|
|
// attribute but only options.
|
|
|
|
//
|
|
|
|
// It is feasible that the data may not have been fetched.
|
|
|
|
data = (data && data.data) || [];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transform the data
|
|
|
|
*/
|
2017-07-18 09:13:16 -05:00
|
|
|
var transform = column.get('transform') || self.defaults.transform;
|
2016-01-15 06:55:13 -06:00
|
|
|
if (transform && _.isFunction(transform)) {
|
|
|
|
// We will transform the data later, when rendering.
|
|
|
|
// It will allow us to generate different data based on the
|
|
|
|
// dependencies.
|
Improvised the 'transform/options' function usage with the Select2Cell.
The current implementaton binds the cell/control object, and the ajax
data in the asychronous Cells/Controls with the 'options' functions
extended from the Select2Cell.
The problem starts when we try to fetch the current model from that
options/transform/filter function to do some operation, which does not
require in most of the cases. Except the privileges control - where we
needed the current model for omitting the existing selected object
during transformation, and filtering.
In order resolved the issue, we need a common object, which is shared
among the Cell. In backgrid, the 'Column' object is mong the cell,
hence - implementation logic has been changed to bid the 'Column' object
with the 'options' function and, passed the 'Cell' object as an
arguments.
Because - we do use the common function 'transform' between 'Control'
and 'Cell', we needed make changes in the Select2Control to pass the
Control object as an arguments.
And, make the changes in the privileges control to use the new
implementation. The same logic is also required in some of the
operations, we will be/are working on the table/column nodes.
2016-04-08 00:30:48 -05:00
|
|
|
column.set('options', transform.bind(column, data));
|
2016-01-15 06:55:13 -06:00
|
|
|
} else {
|
2016-03-15 08:28:16 -05:00
|
|
|
column.set('options', data);
|
2016-01-15 06:55:13 -06:00
|
|
|
}
|
2017-12-13 09:17:17 -06:00
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
if (is_options_cached) {
|
2017-12-13 09:17:17 -06:00
|
|
|
column.set('options_cached', true);
|
|
|
|
}
|
2016-01-15 06:55:13 -06:00
|
|
|
}
|
2018-01-12 01:29:51 -06:00
|
|
|
},
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
Backgrid.Extension.NodeListByIdCell = NodeAjaxOptionsCell.extend({
|
2016-01-15 06:55:13 -06:00
|
|
|
controlClassName: 'pgadmin-node-select backgrid-cell',
|
|
|
|
defaults: _.extend({}, NodeAjaxOptionsCell.prototype.defaults, {
|
|
|
|
url: 'nodes',
|
|
|
|
filter: undefined,
|
Improvised the 'transform/options' function usage with the Select2Cell.
The current implementaton binds the cell/control object, and the ajax
data in the asychronous Cells/Controls with the 'options' functions
extended from the Select2Cell.
The problem starts when we try to fetch the current model from that
options/transform/filter function to do some operation, which does not
require in most of the cases. Except the privileges control - where we
needed the current model for omitting the existing selected object
during transformation, and filtering.
In order resolved the issue, we need a common object, which is shared
among the Cell. In backgrid, the 'Column' object is mong the cell,
hence - implementation logic has been changed to bid the 'Column' object
with the 'options' function and, passed the 'Cell' object as an
arguments.
Because - we do use the common function 'transform' between 'Control'
and 'Cell', we needed make changes in the Select2Control to pass the
Control object as an arguments.
And, make the changes in the privileges control to use the new
implementation. The same logic is also required in some of the
operations, we will be/are working on the table/column nodes.
2016-04-08 00:30:48 -05:00
|
|
|
transform: function(rows, control) {
|
|
|
|
var self = control || this,
|
2018-01-12 01:29:51 -06:00
|
|
|
node = self.column.get('schema_node'),
|
|
|
|
res = [],
|
|
|
|
filter = self.column.get('filter') || function() {
|
|
|
|
return true;
|
|
|
|
};
|
2016-01-15 06:55:13 -06:00
|
|
|
|
|
|
|
filter = filter.bind(self);
|
|
|
|
|
|
|
|
_.each(rows, function(r) {
|
|
|
|
if (filter(r)) {
|
|
|
|
var l = (_.isFunction(node['node_label']) ?
|
2018-01-12 01:29:51 -06:00
|
|
|
(node['node_label']).apply(node, [r, self.model, self]) :
|
|
|
|
r.label),
|
|
|
|
image = (_.isFunction(node['node_image']) ?
|
|
|
|
(node['node_image']).apply(
|
|
|
|
node, [r, self.model, self]
|
|
|
|
) :
|
|
|
|
(node['node_image'] || ('icon-' + node.type)));
|
2016-01-15 06:55:13 -06:00
|
|
|
|
|
|
|
res.push({
|
|
|
|
'value': r._id,
|
|
|
|
'image': image,
|
2018-01-12 01:29:51 -06:00
|
|
|
'label': l,
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
},
|
|
|
|
select2: {
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2016-01-15 06:55:13 -06:00
|
|
|
width: 'style',
|
|
|
|
templateResult: formatNode,
|
2018-01-12 01:29:51 -06:00
|
|
|
templateSelection: formatNode,
|
|
|
|
},
|
|
|
|
}),
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
Backgrid.Extension.NodeListByNameCell = NodeAjaxOptionsCell.extend({
|
2016-01-15 06:55:13 -06:00
|
|
|
controlClassName: 'pgadmin-node-select backgrid-cell',
|
|
|
|
defaults: _.extend({}, NodeAjaxOptionsCell.prototype.defaults, {
|
|
|
|
url: 'nodes',
|
|
|
|
filter: undefined,
|
Improvised the 'transform/options' function usage with the Select2Cell.
The current implementaton binds the cell/control object, and the ajax
data in the asychronous Cells/Controls with the 'options' functions
extended from the Select2Cell.
The problem starts when we try to fetch the current model from that
options/transform/filter function to do some operation, which does not
require in most of the cases. Except the privileges control - where we
needed the current model for omitting the existing selected object
during transformation, and filtering.
In order resolved the issue, we need a common object, which is shared
among the Cell. In backgrid, the 'Column' object is mong the cell,
hence - implementation logic has been changed to bid the 'Column' object
with the 'options' function and, passed the 'Cell' object as an
arguments.
Because - we do use the common function 'transform' between 'Control'
and 'Cell', we needed make changes in the Select2Control to pass the
Control object as an arguments.
And, make the changes in the privileges control to use the new
implementation. The same logic is also required in some of the
operations, we will be/are working on the table/column nodes.
2016-04-08 00:30:48 -05:00
|
|
|
transform: function(rows, control) {
|
|
|
|
var self = control || this,
|
2018-01-12 01:29:51 -06:00
|
|
|
node = self.column.get('schema_node'),
|
|
|
|
res = [],
|
|
|
|
filter = self.column.get('filter') || function() {
|
|
|
|
return true;
|
|
|
|
};
|
2016-01-15 06:55:13 -06:00
|
|
|
|
|
|
|
filter = filter.bind(self);
|
|
|
|
|
|
|
|
_.each(rows, function(r) {
|
|
|
|
if (filter(r)) {
|
|
|
|
var l = (_.isFunction(node['node_label']) ?
|
2018-01-12 01:29:51 -06:00
|
|
|
(node['node_label']).apply(node, [r, self.model, self]) :
|
|
|
|
r.label),
|
|
|
|
image = (_.isFunction(node['node_image']) ?
|
|
|
|
(node['node_image']).apply(
|
|
|
|
node, [r, self.model, self]
|
|
|
|
) :
|
|
|
|
(node['node_image'] || ('icon-' + node.type)));
|
2016-01-15 06:55:13 -06:00
|
|
|
|
|
|
|
res.push({
|
|
|
|
'value': r.label,
|
|
|
|
'image': image,
|
2018-01-12 01:29:51 -06:00
|
|
|
'label': l,
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
},
|
|
|
|
select2: {
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2016-01-15 06:55:13 -06:00
|
|
|
width: 'style',
|
|
|
|
templateResult: formatNode,
|
2018-01-12 01:29:51 -06:00
|
|
|
templateSelection: formatNode,
|
|
|
|
},
|
|
|
|
}),
|
2016-01-15 06:55:13 -06:00
|
|
|
});
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
// Extend the browser's node model class to create a option/value pair
|
|
|
|
Backgrid.Extension.MultiSelectAjaxCell = Backgrid.Extension.NodeAjaxOptionsCell.extend({
|
2016-05-19 10:33:26 -05:00
|
|
|
defaults: _.extend({}, NodeAjaxOptionsCell.prototype.defaults, {
|
|
|
|
transform: undefined,
|
|
|
|
url_with_id: false,
|
|
|
|
select2: {
|
|
|
|
allowClear: true,
|
2019-03-05 08:08:16 -06:00
|
|
|
placeholder: 'Select an item...',
|
2016-05-19 10:33:26 -05:00
|
|
|
width: 'style',
|
2018-01-12 01:29:51 -06:00
|
|
|
multiple: true,
|
2016-05-19 10:33:26 -05:00
|
|
|
},
|
|
|
|
opt: {
|
|
|
|
label: null,
|
|
|
|
value: null,
|
|
|
|
image: null,
|
2018-01-12 01:29:51 -06:00
|
|
|
selected: false,
|
|
|
|
},
|
2016-05-19 10:33:26 -05:00
|
|
|
}),
|
|
|
|
getValueFromDOM: function() {
|
|
|
|
var res = [];
|
|
|
|
|
2018-01-12 01:29:51 -06:00
|
|
|
this.$el.find('select').find(':selected').each(function() {
|
2016-05-19 10:33:26 -05:00
|
|
|
res.push($(this).attr('value'));
|
|
|
|
});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
Backform control for selecting multiple columns.
Usage:
{
id: 'columns', label: '{{ _('Columns') }}',
type: 'collection', group: '{{ _('Definition') }}', editable:true,
canDelete: true, canAdd: true, control: Backform.MultiColumnSelectControl,
deps: ['index'], node: 'column',
model: pgBrowser.Node.Model.extend({
keys: ['column'],
defaults: {
column: undefined
}
})
}
Note: When using this control model should have column attribute. And node property should be column.
2016-03-22 11:52:34 -05:00
|
|
|
/*
|
|
|
|
* Control to select multiple columns.
|
|
|
|
*/
|
2018-01-12 01:29:51 -06:00
|
|
|
Backform.MultiSelectAjaxControl = NodeAjaxOptionsControl.extend({
|
Backform control for selecting multiple columns.
Usage:
{
id: 'columns', label: '{{ _('Columns') }}',
type: 'collection', group: '{{ _('Definition') }}', editable:true,
canDelete: true, canAdd: true, control: Backform.MultiColumnSelectControl,
deps: ['index'], node: 'column',
model: pgBrowser.Node.Model.extend({
keys: ['column'],
defaults: {
column: undefined
}
})
}
Note: When using this control model should have column attribute. And node property should be column.
2016-03-22 11:52:34 -05:00
|
|
|
defaults: _.extend({}, NodeAjaxOptionsControl.prototype.defaults, {
|
|
|
|
select2: {
|
|
|
|
multiple: true,
|
|
|
|
allowClear: true,
|
2018-01-12 01:29:51 -06:00
|
|
|
width: 'style',
|
|
|
|
},
|
|
|
|
}),
|
Backform control for selecting multiple columns.
Usage:
{
id: 'columns', label: '{{ _('Columns') }}',
type: 'collection', group: '{{ _('Definition') }}', editable:true,
canDelete: true, canAdd: true, control: Backform.MultiColumnSelectControl,
deps: ['index'], node: 'column',
model: pgBrowser.Node.Model.extend({
keys: ['column'],
defaults: {
column: undefined
}
})
}
Note: When using this control model should have column attribute. And node property should be column.
2016-03-22 11:52:34 -05:00
|
|
|
});
|
2016-01-15 06:55:13 -06:00
|
|
|
|
2016-01-09 06:29:56 -06:00
|
|
|
return Backform;
|
2018-07-09 07:54:00 -05:00
|
|
|
});
|