define(
['jquery', 'underscore', 'pgadmin', 'backbone', 'backform', 'alertify', 'pgadmin.browser.node'],
function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
var pgBrowser = pgAdmin.Browser;
// Store value in DOM as stringified JSON.
var StringOrJSONFormatter = function() {};
_.extend(StringOrJSONFormatter.prototype, {
fromRaw: function(rawData, model) {
return JSON.stringify(_.escape(rawData));
},
toRaw: function(formattedData, model) {
if (typeof(formattedData) == 'string') {
return _.unescape(formattedData);
}
return JSON.parse(formattedData);
}
});
/*
* 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 =
Backform.SelectControl.extend({
defaults: _.extend(Backform.SelectControl.prototype.defaults, {
url: undefined,
transform: undefined,
url_with_id: false,
first_empty: false,
empty_value: '-- None --',
select2: {
allowClear: true,
placeholder: 'Select from the list',
width: 'style'
}
}),
template: _.template([
'',
'
',
' ',
'
'].join("\n")),
formatter: StringOrJSONFormatter,
initialize: function() {
/*
* Initialization from the original control.
*/
Backform.SelectControl.prototype.initialize.apply(this, arguments);
/*
* We're about to fetch the options required for this control.
*/
var self = this,
url = self.field.get('url') || self.defaults.url,
m = self.model.top || self.model;
// 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'),
node_info = this.field.get('node_info'),
full_url = node.generate_url.apply(
node, [
null, url, this.field.get('node_data'),
this.field.get('url_with_id') || false, node_info
]),
cache_level = this.field.get('cache_level') || node.type,
cache_node = this.field.get('cache_node');
cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node;
/*
* 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(url, node_info, cache_level);
if (this.field.get('version_compitible') &&
(_.isUndefined(data) || _.isNull(data))) {
m.trigger('pgadmin:view:fetching', m, self.field);
$.ajax({
async: false,
url: full_url,
success: function(res) {
/*
* We will cache this data for short period of time for avoiding
* same calls.
*/
data = cache_node.cache(url, node_info, cache_level, res.data);
},
error: function() {
m.trigger('pgadmin:view:fetch:error', m, self.field);
}
});
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
*/
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);
}
}
},
render: function() {
/*
* Let SelectControl render it, we will do our magic on the
* select control in it.
*/
Backform.SelectControl.prototype.render.apply(this, arguments);
var d = this.field.toJSON(),
select2_opts = _.defaults({}, d.select2, this.defaults.select2),
evalF = function(f, d, m) {
return (_.isFunction(f) ? !!f.apply(d, [m]) : !!f);
};
/*
* If select2 options do not have any disabled property on this field
* and schema has disabled property then we need to apply it
*/
if(!_.has(select2_opts, 'disabled') && (d && d.disabled)) {
_.extend(select2_opts, {
disabled: evalF(d.disabled, d, this.model)
});
}
/*
* Add empty option as Select2 requires any empty ''
),
initialize: function () {
Backgrid.Extension.Select2Cell.prototype.initialize.apply(this, arguments);
var col = _.defaults(this.column.toJSON(), this.defaults),
model = this.model, column = this.column,
editable = Backgrid.callByNeed(col.editable, column, model),
optionValues = _.clone(this.optionValues || this.column.get('options'));
var self = this,
url = self.column.get('url') || self.defaults.url,
m = self.model.handler || self.model;
// Hmm - we found the url option.
// That means - we needs to fetch the options from that node.
if (url) {
var node = this.column.get('schema_node'),
node_info = this.column.get('node_info'),
full_url = node.generate_url.apply(
node, [
null, url, this.column.get('node_data'),
this.column.get('url_with_id') || false, node_info
]),
cache_level = this.column.get('cache_level') || node.type,
cache_node = this.column.get('cache_node');
cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node;
/*
* 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(url, node_info, cache_level);
if (this.column.get('version_compitible') &&
(_.isUndefined(data) || _.isNull(data))) {
m.trigger('pgadmin:view:fetching', m, self.column);
$.ajax({
async: false,
url: full_url,
success: function(res) {
/*
* We will cache this data for short period of time for avoiding
* same calls.
*/
data = cache_node.cache(url, node_info, cache_level, res.data);
},
error: function() {
m.trigger('pgadmin:view:fetch:error', m, self.column);
}
});
m.trigger('pgadmin:view:fetched', m, self.column);
}
// 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
*/
transform = this.column.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.column.set('options', transform.bind(self, data));
} else {
self.column.set('options', data);
}
}
},
render: function() {
/*
* Let SelectCell render it, we will do our magic on the
* select control in it.
*/
var col = _.defaults(this.column.toJSON(), this.defaults),
model = this.model, column = this.column,
editable = Backgrid.callByNeed(col.editable, column, model),
optionValues = _.clone(this.optionValues ||
_.isFunction(this.column.get('options')) ?
this.column.get('options').apply(this) :
this.column.get('options')),
select2_opts = _.defaults({}, col.select2, this.defaults.select2),
evalF = function(f, col, m) {
return (_.isFunction(f) ? !!f.apply(col, [m]) : !!f);
};
this.$el.empty();
if (!_.isArray(optionValues)) throw new TypeError("optionValues must be an array");
/*
* Add empty option as Select2 requires any empty '