mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Moving the data model and collection to separate module for better code
handling.
This commit is contained in:
parent
694506453b
commit
2acba32c86
@ -117,15 +117,29 @@ class BrowserModule(PgAdminModule):
|
||||
'preloaded': True
|
||||
})
|
||||
|
||||
scripts.append({
|
||||
'name': 'pgadmin.browser.datamodel',
|
||||
'path': url_for('browser.static', filename='js/datamodel'),
|
||||
'preloaded': True
|
||||
})
|
||||
|
||||
for name, script in [
|
||||
['pgadmin.browser', 'js/browser'],
|
||||
['pgadmin.browser.error', 'js/error'],
|
||||
['pgadmin.browser.error', 'js/error']]:
|
||||
scripts.append({
|
||||
'name': name,
|
||||
'path': url_for('browser.index') + script,
|
||||
'preloaded': True
|
||||
})
|
||||
|
||||
for name, script in [
|
||||
['pgadmin.browser.node', 'js/node'],
|
||||
['pgadmin.browser.collection', 'js/collection']]:
|
||||
scripts.append({
|
||||
'name': name,
|
||||
'path': url_for('browser.index') + script,
|
||||
'preloaded': True
|
||||
'preloaded': True,
|
||||
'deps': ['pgadmin.browser.datamodel']
|
||||
})
|
||||
|
||||
for name, end in [
|
||||
|
865
web/pgadmin/browser/static/js/datamodel.js
Normal file
865
web/pgadmin/browser/static/js/datamodel.js
Normal file
@ -0,0 +1,865 @@
|
||||
define(
|
||||
['underscore', 'pgadmin', 'jquery', 'backbone'],
|
||||
function(_, pgAdmin, $, Backbone) {
|
||||
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
|
||||
pgBrowser.DataModel = Backbone.Model.extend({
|
||||
/*
|
||||
* Parsing the existing data
|
||||
*/
|
||||
parse: function(res) {
|
||||
var self = this;
|
||||
if (res && _.isObject(res) && 'node' in res && res['node']) {
|
||||
self.tnode = _.extend({}, res.node);
|
||||
delete res.node;
|
||||
}
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
var obj, val;
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
obj = self.get(s.id);
|
||||
val = res[s.id];
|
||||
if (_.isArray(val) || _.isObject(val)) {
|
||||
if (!obj || !(obj instanceof Backbone.Collection)) {
|
||||
obj = new (pgBrowser.Node.Collection)(val, {
|
||||
model: ((_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes) ?
|
||||
pgBrowser.Nodes[s.model].model : s.model),
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
parse: true,
|
||||
silent: true,
|
||||
attrName: s.id
|
||||
});
|
||||
self.set(s.id, obj, {silent: true, parse: true});
|
||||
} else {
|
||||
obj.reset(val, {silent: true, parse: true});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (obj)
|
||||
delete obj;
|
||||
obj = null;
|
||||
}
|
||||
self.set(s.id, obj, {silent: true});
|
||||
res[s.id] = obj;
|
||||
break;
|
||||
case 'model':
|
||||
obj = self.get(s.id);
|
||||
val = res[s.id];
|
||||
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)(
|
||||
obj, {
|
||||
silent: true, top: self.top || self, handler: self,
|
||||
attrName: s.id
|
||||
}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(obj, {
|
||||
silent: true, top: self.top || self, handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
obj.set(val, {parse: true, silent: true});
|
||||
} else {
|
||||
if (obj)
|
||||
delete obj;
|
||||
obj = null;
|
||||
}
|
||||
res[s.id] = obj;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
primary_key: function() {
|
||||
if (this.keys && _.isArray(this.keys)) {
|
||||
var res = {}, self = this;
|
||||
|
||||
_.each(self.keys, function(k) {
|
||||
res[k] = self.attributes[k];
|
||||
});
|
||||
|
||||
return JSON.stringify(res);
|
||||
}
|
||||
return this.cid;
|
||||
},
|
||||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
Backbone.Model.prototype.initialize.apply(self, arguments);
|
||||
|
||||
if (_.isUndefined(options) || _.isNull(options)) {
|
||||
options = attributes || {};
|
||||
attributes = null;
|
||||
}
|
||||
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = {};
|
||||
self.objects = [];
|
||||
self.attrName = options.attrName,
|
||||
self.top = (options.top || self.collection && self.collection.top || self.collection || self);
|
||||
self.handler = options.handler ||
|
||||
(self.collection && self.collection.handler);
|
||||
self.trackChanges = false;
|
||||
self.errorModel = new Backbone.Model();
|
||||
self.node_info = options.node_info;
|
||||
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
var obj = self.get(s.id);
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
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)(obj, {
|
||||
model: node.model,
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
} else {
|
||||
obj = new (pgBrowser.Node.Collection)(obj, {
|
||||
model: s.model,
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
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, {
|
||||
top: self.top || self, handler: self, attrName: s.id
|
||||
}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(
|
||||
obj, {
|
||||
top: self.top || self, handler: self, attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
obj.name = s.id;
|
||||
self.objects.push(s.id);
|
||||
self.set(s.id, obj, {silent: true});
|
||||
});
|
||||
}
|
||||
|
||||
if (self.handler && self.handler.trackChanges) {
|
||||
self.startNewSession();
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
sessChanged: function() {
|
||||
var self = this;
|
||||
|
||||
return (_.size(self.sessAttrs) > 0 ||
|
||||
_.some(self.objects, function(k) {
|
||||
var obj = self.get(k);
|
||||
if (!(_.isNull(obj) || _.isUndefined(obj))) {
|
||||
return obj.sessChanged();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
sessValid: function() {
|
||||
var self = this;
|
||||
if ('validate' in self && _.isFunction(self.validate) &&
|
||||
_.isString(self.validate.apply(self))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
set: function(key, val, options) {
|
||||
var opts = _.isObject(key) ? val : options;
|
||||
|
||||
var res = Backbone.Model.prototype.set.call(this, key, val, options);
|
||||
|
||||
if ((opts&& opts.intenal) || !this.trackChanges) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key != null && res) {
|
||||
var attrs = {};
|
||||
var self = this;
|
||||
|
||||
attrChanged = function(v, k) {
|
||||
if (k in self.objects) {
|
||||
return;
|
||||
}
|
||||
attrs[k] = v;
|
||||
if (self.origSessAttrs[k] == v) {
|
||||
delete self.sessAttrs[k];
|
||||
} else {
|
||||
self.sessAttrs[k] = v;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
if (typeof key === 'object') {
|
||||
_.each(key, attrChanged);
|
||||
} else {
|
||||
attrChanged(val, key);
|
||||
}
|
||||
|
||||
self.trigger('pgadmin-session:set', self, attrs);
|
||||
|
||||
if ('validate' in self && typeof(self['validate']) === 'function') {
|
||||
|
||||
var msg = self.validate(_.keys(attrs));
|
||||
|
||||
/*
|
||||
* If any parent present, we will need to inform the parent - that
|
||||
* I have some issues/fixed the issue.
|
||||
*
|
||||
* If not parent found, we will raise the issue
|
||||
*/
|
||||
if (msg != null) {
|
||||
if (self.collection || self.handler) {
|
||||
(self.collection || self.handler).trigger(
|
||||
'pgadmin-session:model:invalid', msg, self
|
||||
);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
} else if (_.size(self.errorModel.attributes) == 0) {
|
||||
if (self.collection || self.handler) {
|
||||
(self.collection || self.handler).trigger(
|
||||
'pgadmin-session:model:valid', self
|
||||
);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
/*
|
||||
* We do support modified data only through session by tracking changes.
|
||||
*
|
||||
* In normal mode, we will use the toJSON function of Backbone.Model.
|
||||
* In session mode, we will return all the modified data only. And, the
|
||||
* objects (collection, and model) will be return as stringified JSON,
|
||||
* only from the parent object.
|
||||
*/
|
||||
toJSON: function(session, method) {
|
||||
var self = this, res, isNew = self.isNew();
|
||||
|
||||
session = (typeof(session) != "undefined" && session == true);
|
||||
|
||||
if (!session || isNew) {
|
||||
res = Backbone.Model.prototype.toJSON.call(this, arguments);
|
||||
} else {
|
||||
res = {};
|
||||
res[self.idAttribute || '_id'] = self.get(self.idAttribute || '_id');
|
||||
res = _.extend(res, self.sessAttrs);
|
||||
}
|
||||
|
||||
/*
|
||||
* We do have number objects (models, collections), which needs to be
|
||||
* converted to JSON data manually.
|
||||
*/
|
||||
_.each(
|
||||
self.objects,
|
||||
function(k) {
|
||||
var obj = self.get(k);
|
||||
/*
|
||||
* For session changes, we only need the modified data to be
|
||||
* transformed to JSON data.
|
||||
*/
|
||||
if (session) {
|
||||
if ((obj.sessChanged && obj.sessChanged()) || isNew) {
|
||||
res[k] = obj && obj.toJSON(!isNew);
|
||||
/*
|
||||
* We will run JSON.stringify(..) only from the main object,
|
||||
* not for the JSON object within the objects, that only when
|
||||
* HTTP method is 'GET'.
|
||||
*
|
||||
* We do stringify the object, so that - it will not be
|
||||
* translated to wierd format using jQuery.
|
||||
*/
|
||||
if (obj && method && method == 'GET') {
|
||||
res[k] = JSON.stringify(res[k]);
|
||||
}
|
||||
} else {
|
||||
delete res[k];
|
||||
}
|
||||
} else {
|
||||
res[k] = (obj && obj.toJSON());
|
||||
}
|
||||
});
|
||||
return res;
|
||||
},
|
||||
startNewSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
self.trigger('pgadmin-session:stop', self);
|
||||
self.off('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onChildValid);
|
||||
}
|
||||
|
||||
self.trackChanges = true;
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = _.clone(self.attributes);
|
||||
|
||||
var res = false;
|
||||
|
||||
_.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)) {
|
||||
obj.startNewSession();
|
||||
}
|
||||
});
|
||||
|
||||
// Let people know, I have started session hanlding
|
||||
self.trigger('pgadmin-session:start', self);
|
||||
|
||||
// Let me listen to the my child invalid/valid messages
|
||||
self.on('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.on('pgadmin-session:model:valid', self.onChildValid);
|
||||
|
||||
},
|
||||
onChildInvalid: function(msg, obj) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges && obj) {
|
||||
var objName = obj.attrName;
|
||||
|
||||
if (!objName) {
|
||||
var hasPrimaryKey = obj.primary_key &&
|
||||
typeof(obj.primary_key) === 'function';
|
||||
key = hasPrimaryKey ? obj.primary_key() : obj.cid,
|
||||
comparator = hasPrimaryKey ?
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.primary_key() === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} :
|
||||
function(k) {
|
||||
var o = self.get(k);
|
||||
|
||||
if (o.cid === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
_.findIndex(self.objects, comparator);
|
||||
}
|
||||
|
||||
if (objName && !self.errorModel.has(objName)) {
|
||||
/*
|
||||
* We will trigger error information only once.
|
||||
*/
|
||||
if (!_.size(self.errorModel.attributes)) {
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
self.errorModel.set(objName, msg);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
onChildValid: function(obj) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges && obj) {
|
||||
var objName = obj.attrName;
|
||||
|
||||
if (!objName) {
|
||||
var hasPrimaryKey = (obj.primary_key &&
|
||||
(typeof(obj.primary_key) === 'function'));
|
||||
key = hasPrimaryKey ? obj.primary_key() : obj.cid,
|
||||
comparator = hasPrimaryKey ?
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.primary_key() === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} :
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.cid === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
_.findIndex(self.objects, comparator);
|
||||
}
|
||||
|
||||
if (objName && self.errorModel.has(objName)) {
|
||||
|
||||
self.errorModel.unset(objName);
|
||||
|
||||
/*
|
||||
* We will trigger validation information
|
||||
*/
|
||||
if (_.size(self.errorModel.attributes) == 0) {
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger(
|
||||
'pgadmin-session:valid', self.sessChanged(), self
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
stopSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
self.off('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onChildValid);
|
||||
}
|
||||
|
||||
self.trackChanges = false;
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = {};
|
||||
|
||||
_.each(self.objects, function(o) {
|
||||
var obj = self.get(o);
|
||||
|
||||
if (_.isUndefined(obj) || _.isNull(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.origSessAttrs[o] = null;
|
||||
delete self.origSessAttrs[o];
|
||||
|
||||
if (obj && 'stopSession' in obj && _.isFunction(obj.stopSession)) {
|
||||
obj.stopSession();
|
||||
}
|
||||
});
|
||||
|
||||
self.trigger('pgadmin-session:stop');
|
||||
}
|
||||
});
|
||||
|
||||
pgBrowser.DataCollection = Backbone.Collection.extend({
|
||||
// Model collection
|
||||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
/*
|
||||
* Session changes will be kept in this object.
|
||||
*/
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
self.top = options.top || self;
|
||||
self.attrName = options.attrName;
|
||||
self.handler = options.handler;
|
||||
self.trackChanges = false;
|
||||
|
||||
/*
|
||||
* Listen to the model changes for the session changes.
|
||||
*/
|
||||
self.on('add', self.onModelAdd);
|
||||
self.on('remove', self.onModelRemove);
|
||||
self.on('change', self.onModelChange);
|
||||
|
||||
/*
|
||||
* We need to start the session, if the handler is already in session
|
||||
* tracking mode.
|
||||
*/
|
||||
if (self.handler && self.handler.trackChanges) {
|
||||
self.startNewSession();
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
startNewSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// We're stopping the existing session.
|
||||
self.trigger('pgadmin-session:stop', self);
|
||||
|
||||
self.off('pgadmin-session:model:invalid', self.onModelInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onModelValid);
|
||||
}
|
||||
|
||||
self.trackChanges = true;
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
|
||||
_.each(self.models, function(m) {
|
||||
if ('startNewSession' in m && _.isFunction(m.startNewSession)) {
|
||||
m.startNewSession();
|
||||
}
|
||||
if ('validate' in m && typeof(m.validate) === 'function') {
|
||||
var msg = m.validate();
|
||||
|
||||
if (msg) {
|
||||
self.sessAttrs['invalid'].push(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Let people know, I have started session hanlding
|
||||
self.trigger('pgadmin-session:start', self);
|
||||
|
||||
self.on('pgadmin-session:model:invalid', self.onModelInvalid);
|
||||
self.on('pgadmin-session:model:valid', self.onModelValid);
|
||||
},
|
||||
onModelInvalid: function(msg, m) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// Do not add the existing invalid object
|
||||
if (self.objFindInSession(m, 'invalid') == -1) {
|
||||
self.sessAttrs['invalid'].push(m);
|
||||
|
||||
// Inform the parent that - I am an invalid object.
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelValid: function(m) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// Find the object the invalid list, if found remove it from the list
|
||||
// and inform the parent that - I am a valid object now.
|
||||
var idx = self.objFindInSession(m, 'invalid');
|
||||
if (idx != -1) {
|
||||
self.sessAttrs['invalid'].splice(m, 1);
|
||||
|
||||
// Inform the parent that - I am the valid object.
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
stopSession: function() {
|
||||
var self = this;
|
||||
|
||||
self.trackChanges = false;
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
|
||||
_.each(self.models, function(m) {
|
||||
if ('stopSession' in m && _.isFunction(m.stopSession)) {
|
||||
m.stopSession();
|
||||
}
|
||||
});
|
||||
},
|
||||
sessChanged: function() {
|
||||
return (
|
||||
this.sessAttrs['changed'].length > 0 ||
|
||||
this.sessAttrs['added'].length > 0 ||
|
||||
this.sessAttrs['deleted'].length > 0
|
||||
);
|
||||
},
|
||||
/*
|
||||
* We do support the changes through session tracking in general.
|
||||
*
|
||||
* In normal mode, we will use the general toJSON(..) function of
|
||||
* Backbone.Colletion.
|
||||
*
|
||||
* In session mode, we will return session changes as:
|
||||
* We will be returning the session changes as:
|
||||
* {
|
||||
* 'added': [JSON of each new model],
|
||||
* 'delete': [JSON of each deleted model],
|
||||
* 'changed': [JSON of each modified model with session changes]
|
||||
* }
|
||||
*/
|
||||
toJSON: function(session) {
|
||||
var self = this,
|
||||
session = (typeof(session) != "undefined" && session == true);
|
||||
|
||||
if (!session) {
|
||||
return Backbone.Collection.prototype.toJSON.call(self);
|
||||
} else {
|
||||
var res = {};
|
||||
|
||||
res['added'] = [];
|
||||
_.each(this.sessAttrs['added'], function(o) {
|
||||
res['added'].push(o.toJSON());
|
||||
});
|
||||
if (res['added'].length == 0) {
|
||||
delete res['added'];
|
||||
}
|
||||
res['changed'] = [];
|
||||
_.each(self.sessAttrs['changed'], function(o) {
|
||||
res['changed'].push(o.toJSON(true));
|
||||
});
|
||||
if (res['changed'].length == 0) {
|
||||
delete res['changed'];
|
||||
}
|
||||
res['deleted'] = [];
|
||||
_.each(self.sessAttrs['deleted'], function(o) {
|
||||
res['deleted'].push(o.toJSON());
|
||||
});
|
||||
if (res['deleted'].length == 0) {
|
||||
delete res['deleted'];
|
||||
}
|
||||
|
||||
return (_.size(res) == 0 ? null : res);
|
||||
}
|
||||
},
|
||||
objFindInSession: function(m, type) {
|
||||
var hasPrimaryKey = m.primary_key &&
|
||||
typeof(m.primary_key) == 'function',
|
||||
key = hasPrimaryKey ? m.primary_key() : m.cid,
|
||||
comparator = hasPrimaryKey ? function(o) {
|
||||
return (o.primary_key() === key);
|
||||
} : function(o) {
|
||||
return (o.cid === key);
|
||||
};
|
||||
|
||||
return (_.findIndex(this.sessAttrs[type], comparator));
|
||||
},
|
||||
onModelAdd: function(obj) {
|
||||
|
||||
if (!this.trackChanges)
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
msg,
|
||||
isAlreadyInvalid = (_.size(self.sessAttrs['invalid']) != 0),
|
||||
idx = self.objFindInSession(obj, 'deleted');
|
||||
|
||||
if ('validate' in obj && typeof(obj.validate) === 'function') {
|
||||
msg = obj.validate();
|
||||
|
||||
if (msg) {
|
||||
self.sessAttrs['invalid'].push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Hmm.. - it was originally deleted from this collection, we should
|
||||
// remove it from the 'deleted' list.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['deleted'].splice(idx, 1);
|
||||
|
||||
// It has been changed originally!
|
||||
if ((!'sessChanged' in obj) || obj.sessChanged()) {
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
}
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:added', self, obj);
|
||||
|
||||
/*
|
||||
* If the collection was already invalid, we don't need to inform the
|
||||
* parent, or raise the event for the invalid status.
|
||||
*/
|
||||
if (!isAlreadyInvalid && !_.isUndefined(msg)) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
self.sessAttrs['added'].push(obj);
|
||||
|
||||
/*
|
||||
* Session has been changed
|
||||
*/
|
||||
(self.handler || self).trigger('pgadmin-session:added', self, obj);
|
||||
|
||||
/*
|
||||
* If the collection was already invalid, we don't need to inform the
|
||||
* parent, or raise the event for the invalid status.
|
||||
*/
|
||||
if (!isAlreadyInvalid && !_.isUndefined(msg)) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelRemove: function(obj) {
|
||||
|
||||
if (!this.trackChanges)
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
idx = self.objFindInSession(obj, 'added'),
|
||||
copy = _.clone(obj);
|
||||
|
||||
// We need to remove it from the invalid object list first.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['invalid'].splice(idx, 1);
|
||||
}
|
||||
|
||||
idx = self.objFindInSession(obj, 'added');
|
||||
// Hmm - it was newly added, we can safely remove it.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['added'].splice(idx, 1);
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
|
||||
if (_.size(self.sessAttrs['invalid']) == 0) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hmm - it was changed in this session, we should remove it from the
|
||||
// changed models.
|
||||
idx = self.objFindInSession(obj, 'changed');
|
||||
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['changed'].splice(idx, 1);
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
} else {
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
}
|
||||
|
||||
self.sessAttrs['deleted'].push(obj);
|
||||
|
||||
/*
|
||||
* This object has been remove, that means - we can safely say, it has been
|
||||
* modified.
|
||||
*/
|
||||
if (_.size(self.sessAttrs['invalid']) == 0) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', true, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelChange: function(obj) {
|
||||
|
||||
if (!this.trackChanges || !(obj instanceof pgBrowser.Node.Model))
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
idx = self.objFindInSession(obj, 'added');
|
||||
|
||||
// It was newly added model, we don't need to add into the changed
|
||||
// list.
|
||||
if (idx >= 0) {
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
idx = self.objFindInSession(obj, 'changed');
|
||||
|
||||
if (!'sessChanged' in obj) {
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
if (idx >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (idx >= 0) {
|
||||
|
||||
|
||||
if (!obj.sessChanged()) {
|
||||
// This object is no more updated, removing it from the changed
|
||||
// models list.
|
||||
self.sessAttrs['changed'].splice(idx, 1);
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:changed',self, obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:changed',self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
return pgBrowser;
|
||||
});
|
@ -1,10 +1,9 @@
|
||||
define(
|
||||
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser.menu',
|
||||
'backbone', 'alertify', 'backform', 'pgadmin.backform', 'wcdocker',
|
||||
'pgadmin.alertifyjs'],
|
||||
function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
'backbone', 'alertify', 'pgadmin.browser.datamodel', 'backform',
|
||||
'pgadmin.backform', 'wcdocker', 'pgadmin.alertifyjs'],
|
||||
function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
|
||||
|
||||
var pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
var wcDocker = window.wcDocker;
|
||||
|
||||
// It has already been defined.
|
||||
@ -1073,864 +1072,9 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
});
|
||||
},
|
||||
// Base class for Node Data Collection
|
||||
Collection: Backbone.Collection.extend({
|
||||
// Model collection
|
||||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
/*
|
||||
* Session changes will be kept in this object.
|
||||
*/
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
self.top = options.top || self;
|
||||
self.attrName = options.attrName;
|
||||
self.handler = options.handler;
|
||||
self.trackChanges = false;
|
||||
|
||||
/*
|
||||
* Listen to the model changes for the session changes.
|
||||
*/
|
||||
self.on('add', self.onModelAdd);
|
||||
self.on('remove', self.onModelRemove);
|
||||
self.on('change', self.onModelChange);
|
||||
|
||||
/*
|
||||
* We need to start the session, if the handler is already in session
|
||||
* tracking mode.
|
||||
*/
|
||||
if (self.handler && self.handler.trackChanges) {
|
||||
self.startNewSession();
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
startNewSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// We're stopping the existing session.
|
||||
self.trigger('pgadmin-session:stop', self);
|
||||
|
||||
self.off('pgadmin-session:model:invalid', self.onModelInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onModelValid);
|
||||
}
|
||||
|
||||
self.trackChanges = true;
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
|
||||
_.each(self.models, function(m) {
|
||||
if ('startNewSession' in m && _.isFunction(m.startNewSession)) {
|
||||
m.startNewSession();
|
||||
}
|
||||
if ('validate' in m && typeof(m.validate) === 'function') {
|
||||
var msg = m.validate();
|
||||
|
||||
if (msg) {
|
||||
self.sessAttrs['invalid'].push(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Let people know, I have started session hanlding
|
||||
self.trigger('pgadmin-session:start', self);
|
||||
|
||||
self.on('pgadmin-session:model:invalid', self.onModelInvalid);
|
||||
self.on('pgadmin-session:model:valid', self.onModelValid);
|
||||
},
|
||||
onModelInvalid: function(msg, m) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// Do not add the existing invalid object
|
||||
if (self.objFindInSession(m, 'invalid') == -1) {
|
||||
self.sessAttrs['invalid'].push(m);
|
||||
|
||||
// Inform the parent that - I am an invalid object.
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelValid: function(m) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
// Find the object the invalid list, if found remove it from the list
|
||||
// and inform the parent that - I am a valid object now.
|
||||
var idx = self.objFindInSession(m, 'invalid');
|
||||
if (idx != -1) {
|
||||
self.sessAttrs['invalid'].splice(m, 1);
|
||||
|
||||
// Inform the parent that - I am the valid object.
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
stopSession: function() {
|
||||
var self = this;
|
||||
|
||||
self.trackChanges = false;
|
||||
self.sessAttrs = {
|
||||
'changed': [],
|
||||
'added': [],
|
||||
'deleted': [],
|
||||
'invalid': []
|
||||
};
|
||||
|
||||
_.each(self.models, function(m) {
|
||||
if ('stopSession' in m && _.isFunction(m.stopSession)) {
|
||||
m.stopSession();
|
||||
}
|
||||
});
|
||||
},
|
||||
sessChanged: function() {
|
||||
return (
|
||||
this.sessAttrs['changed'].length > 0 ||
|
||||
this.sessAttrs['added'].length > 0 ||
|
||||
this.sessAttrs['deleted'].length > 0
|
||||
);
|
||||
},
|
||||
/*
|
||||
* We do support the changes through session tracking in general.
|
||||
*
|
||||
* In normal mode, we will use the general toJSON(..) function of
|
||||
* Backbone.Colletion.
|
||||
*
|
||||
* In session mode, we will return session changes as:
|
||||
* We will be returning the session changes as:
|
||||
* {
|
||||
* 'added': [JSON of each new model],
|
||||
* 'delete': [JSON of each deleted model],
|
||||
* 'changed': [JSON of each modified model with session changes]
|
||||
* }
|
||||
*/
|
||||
toJSON: function(session) {
|
||||
var self = this,
|
||||
session = (typeof(session) != "undefined" && session == true);
|
||||
|
||||
if (!session) {
|
||||
return Backbone.Collection.prototype.toJSON.call(self);
|
||||
} else {
|
||||
var res = {};
|
||||
|
||||
res['added'] = [];
|
||||
_.each(this.sessAttrs['added'], function(o) {
|
||||
res['added'].push(o.toJSON());
|
||||
});
|
||||
if (res['added'].length == 0) {
|
||||
delete res['added'];
|
||||
}
|
||||
res['changed'] = [];
|
||||
_.each(self.sessAttrs['changed'], function(o) {
|
||||
res['changed'].push(o.toJSON(true));
|
||||
});
|
||||
if (res['changed'].length == 0) {
|
||||
delete res['changed'];
|
||||
}
|
||||
res['deleted'] = [];
|
||||
_.each(self.sessAttrs['deleted'], function(o) {
|
||||
res['deleted'].push(o.toJSON());
|
||||
});
|
||||
if (res['deleted'].length == 0) {
|
||||
delete res['deleted'];
|
||||
}
|
||||
|
||||
return (_.size(res) == 0 ? null : res);
|
||||
}
|
||||
},
|
||||
objFindInSession: function(m, type) {
|
||||
var hasPrimaryKey = m.primary_key &&
|
||||
typeof(m.primary_key) == 'function',
|
||||
key = hasPrimaryKey ? m.primary_key() : m.cid,
|
||||
comparator = hasPrimaryKey ? function(o) {
|
||||
return (o.primary_key() === key);
|
||||
} : function(o) {
|
||||
return (o.cid === key);
|
||||
};
|
||||
|
||||
return (_.findIndex(this.sessAttrs[type], comparator));
|
||||
},
|
||||
onModelAdd: function(obj) {
|
||||
|
||||
if (!this.trackChanges)
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
msg,
|
||||
isAlreadyInvalid = (_.size(self.sessAttrs['invalid']) != 0),
|
||||
idx = self.objFindInSession(obj, 'deleted');
|
||||
|
||||
if ('validate' in obj && typeof(obj.validate) === 'function') {
|
||||
msg = obj.validate();
|
||||
|
||||
if (msg) {
|
||||
self.sessAttrs['invalid'].push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Hmm.. - it was originally deleted from this collection, we should
|
||||
// remove it from the 'deleted' list.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['deleted'].splice(idx, 1);
|
||||
|
||||
// It has been changed originally!
|
||||
if ((!'sessChanged' in obj) || obj.sessChanged()) {
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
}
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:added', self, obj);
|
||||
|
||||
/*
|
||||
* If the collection was already invalid, we don't need to inform the
|
||||
* parent, or raise the event for the invalid status.
|
||||
*/
|
||||
if (!isAlreadyInvalid && !_.isUndefined(msg)) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
self.sessAttrs['added'].push(obj);
|
||||
|
||||
/*
|
||||
* Session has been changed
|
||||
*/
|
||||
(self.handler || self).trigger('pgadmin-session:added', self, obj);
|
||||
|
||||
/*
|
||||
* If the collection was already invalid, we don't need to inform the
|
||||
* parent, or raise the event for the invalid status.
|
||||
*/
|
||||
if (!isAlreadyInvalid && !_.isUndefined(msg)) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelRemove: function(obj) {
|
||||
|
||||
if (!this.trackChanges)
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
idx = self.objFindInSession(obj, 'added'),
|
||||
copy = _.clone(obj);
|
||||
|
||||
// We need to remove it from the invalid object list first.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['invalid'].splice(idx, 1);
|
||||
}
|
||||
|
||||
idx = self.objFindInSession(obj, 'added');
|
||||
// Hmm - it was newly added, we can safely remove it.
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['added'].splice(idx, 1);
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
|
||||
if (_.size(self.sessAttrs['invalid']) == 0) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hmm - it was changed in this session, we should remove it from the
|
||||
// changed models.
|
||||
idx = self.objFindInSession(obj, 'changed');
|
||||
|
||||
if (idx >= 0) {
|
||||
self.sessAttrs['changed'].splice(idx, 1);
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
} else {
|
||||
(self.handler || self).trigger('pgadmin-session:removed', self, copy);
|
||||
}
|
||||
|
||||
self.sessAttrs['deleted'].push(obj);
|
||||
|
||||
/*
|
||||
* This object has been remove, that means - we can safely say, it has been
|
||||
* modified.
|
||||
*/
|
||||
if (_.size(self.sessAttrs['invalid']) == 0) {
|
||||
if (self.handler) {
|
||||
self.handler.trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', true, self);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
onModelChange: function(obj) {
|
||||
|
||||
if (!this.trackChanges || !(obj instanceof pgBrowser.Node.Model))
|
||||
return true;
|
||||
|
||||
var self = this,
|
||||
idx = self.objFindInSession(obj, 'added');
|
||||
|
||||
// It was newly added model, we don't need to add into the changed
|
||||
// list.
|
||||
if (idx >= 0) {
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
idx = self.objFindInSession(obj, 'changed');
|
||||
|
||||
if (!'sessChanged' in obj) {
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
if (idx >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (idx >= 0) {
|
||||
|
||||
|
||||
if (!obj.sessChanged()) {
|
||||
// This object is no more updated, removing it from the changed
|
||||
// models list.
|
||||
self.sessAttrs['changed'].splice(idx, 1);
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:changed',self, obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
(self.handler || self).trigger('pgadmin-session:changed',self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
self.sessAttrs['changed'].push(obj);
|
||||
(self.handler || self).trigger('pgadmin-session:changed', self, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
}),
|
||||
|
||||
Collection: pgBrowser.DataCollection,
|
||||
// Base class for Node Data Model
|
||||
Model: Backbone.Model.extend({
|
||||
/*
|
||||
* Parsing the existing data
|
||||
*/
|
||||
parse: function(res) {
|
||||
var self = this;
|
||||
if (res && _.isObject(res) && 'node' in res && res['node']) {
|
||||
self.tnode = _.extend({}, res.node);
|
||||
delete res.node;
|
||||
}
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
var obj, val;
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
obj = self.get(s.id);
|
||||
val = res[s.id];
|
||||
if (_.isArray(val) || _.isObject(val)) {
|
||||
if (!obj || !(obj instanceof Backbone.Collection)) {
|
||||
obj = new (pgBrowser.Node.Collection)(val, {
|
||||
model: ((_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes) ?
|
||||
pgBrowser.Nodes[s.model].model : s.model),
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
parse: true,
|
||||
silent: true,
|
||||
attrName: s.id
|
||||
});
|
||||
self.set(s.id, obj, {silent: true, parse: true});
|
||||
} else {
|
||||
obj.reset(val, {silent: true, parse: true});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (obj)
|
||||
delete obj;
|
||||
obj = null;
|
||||
}
|
||||
self.set(s.id, obj, {silent: true});
|
||||
res[s.id] = obj;
|
||||
break;
|
||||
case 'model':
|
||||
obj = self.get(s.id);
|
||||
val = res[s.id];
|
||||
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)(
|
||||
obj, {
|
||||
silent: true, top: self.top || self, handler: self,
|
||||
attrName: s.id
|
||||
}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(obj, {
|
||||
silent: true, top: self.top || self, handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
obj.set(val, {parse: true, silent: true});
|
||||
} else {
|
||||
if (obj)
|
||||
delete obj;
|
||||
obj = null;
|
||||
}
|
||||
res[s.id] = obj;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
primary_key: function() {
|
||||
if (this.keys && _.isArray(this.keys)) {
|
||||
var res = {}, self = this;
|
||||
|
||||
_.each(self.keys, function(k) {
|
||||
res[k] = self.attributes[k];
|
||||
});
|
||||
|
||||
return JSON.stringify(res);
|
||||
}
|
||||
return this.cid;
|
||||
},
|
||||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
Backbone.Model.prototype.initialize.apply(self, arguments);
|
||||
|
||||
if (_.isUndefined(options) || _.isNull(options)) {
|
||||
options = attributes || {};
|
||||
attributes = null;
|
||||
}
|
||||
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = {};
|
||||
self.objects = [];
|
||||
self.attrName = options.attrName,
|
||||
self.top = (options.top || self.collection && self.collection.top || self.collection || self);
|
||||
self.handler = options.handler ||
|
||||
(self.collection && self.collection.handler);
|
||||
self.trackChanges = false;
|
||||
self.errorModel = new Backbone.Model();
|
||||
self.node_info = options.node_info;
|
||||
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
var obj = self.get(s.id);
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
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)(obj, {
|
||||
model: node.model,
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
} else {
|
||||
obj = new (pgBrowser.Node.Collection)(obj, {
|
||||
model: s.model,
|
||||
top: self.top || self,
|
||||
handler: self,
|
||||
attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
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, {
|
||||
top: self.top || self, handler: self, attrName: s.id
|
||||
}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(
|
||||
obj, {
|
||||
top: self.top || self, handler: self, attrName: s.id
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
obj.name = s.id;
|
||||
self.objects.push(s.id);
|
||||
self.set(s.id, obj, {silent: true});
|
||||
});
|
||||
}
|
||||
|
||||
if (self.handler && self.handler.trackChanges) {
|
||||
self.startNewSession();
|
||||
}
|
||||
|
||||
return self;
|
||||
},
|
||||
sessChanged: function() {
|
||||
var self = this;
|
||||
|
||||
return (_.size(self.sessAttrs) > 0 ||
|
||||
_.some(self.objects, function(k) {
|
||||
var obj = self.get(k);
|
||||
if (!(_.isNull(obj) || _.isUndefined(obj))) {
|
||||
return obj.sessChanged();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
sessValid: function() {
|
||||
var self = this;
|
||||
if ('validate' in self && _.isFunction(self.validate) &&
|
||||
_.isString(self.validate.apply(self))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
set: function(key, val, options) {
|
||||
var opts = _.isObject(key) ? val : options;
|
||||
|
||||
var res = Backbone.Model.prototype.set.call(this, key, val, options);
|
||||
|
||||
if ((opts&& opts.intenal) || !this.trackChanges) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key != null && res) {
|
||||
var attrs = {};
|
||||
var self = this;
|
||||
|
||||
attrChanged = function(v, k) {
|
||||
if (k in self.objects) {
|
||||
return;
|
||||
}
|
||||
attrs[k] = v;
|
||||
if (self.origSessAttrs[k] == v) {
|
||||
delete self.sessAttrs[k];
|
||||
} else {
|
||||
self.sessAttrs[k] = v;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
if (typeof key === 'object') {
|
||||
_.each(key, attrChanged);
|
||||
} else {
|
||||
attrChanged(val, key);
|
||||
}
|
||||
|
||||
self.trigger('pgadmin-session:set', self, attrs);
|
||||
|
||||
if ('validate' in self && typeof(self['validate']) === 'function') {
|
||||
|
||||
var msg = self.validate(_.keys(attrs));
|
||||
|
||||
/*
|
||||
* If any parent present, we will need to inform the parent - that
|
||||
* I have some issues/fixed the issue.
|
||||
*
|
||||
* If not parent found, we will raise the issue
|
||||
*/
|
||||
if (msg != null) {
|
||||
if (self.collection || self.handler) {
|
||||
(self.collection || self.handler).trigger(
|
||||
'pgadmin-session:model:invalid', msg, self
|
||||
);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
} else if (_.size(self.errorModel.attributes) == 0) {
|
||||
if (self.collection || self.handler) {
|
||||
(self.collection || self.handler).trigger(
|
||||
'pgadmin-session:model:valid', self
|
||||
);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:valid', self.sessChanged(), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
/*
|
||||
* We do support modified data only through session by tracking changes.
|
||||
*
|
||||
* In normal mode, we will use the toJSON function of Backbone.Model.
|
||||
* In session mode, we will return all the modified data only. And, the
|
||||
* objects (collection, and model) will be return as stringified JSON,
|
||||
* only from the parent object.
|
||||
*/
|
||||
toJSON: function(session, method) {
|
||||
var self = this, res, isNew = self.isNew();
|
||||
|
||||
session = (typeof(session) != "undefined" && session == true);
|
||||
|
||||
if (!session || isNew) {
|
||||
res = Backbone.Model.prototype.toJSON.call(this, arguments);
|
||||
} else {
|
||||
res = {};
|
||||
res[self.idAttribute || '_id'] = self.get(self.idAttribute || '_id');
|
||||
res = _.extend(res, self.sessAttrs);
|
||||
}
|
||||
|
||||
/*
|
||||
* We do have number objects (models, collections), which needs to be
|
||||
* converted to JSON data manually.
|
||||
*/
|
||||
_.each(
|
||||
self.objects,
|
||||
function(k) {
|
||||
var obj = self.get(k);
|
||||
/*
|
||||
* For session changes, we only need the modified data to be
|
||||
* transformed to JSON data.
|
||||
*/
|
||||
if (session) {
|
||||
if ((obj.sessChanged && obj.sessChanged()) || isNew) {
|
||||
res[k] = obj && obj.toJSON(!isNew);
|
||||
/*
|
||||
* We will run JSON.stringify(..) only from the main object,
|
||||
* not for the JSON object within the objects, that only when
|
||||
* HTTP method is 'GET'.
|
||||
*
|
||||
* We do stringify the object, so that - it will not be
|
||||
* translated to wierd format using jQuery.
|
||||
*/
|
||||
if (obj && method && method == 'GET') {
|
||||
res[k] = JSON.stringify(res[k]);
|
||||
}
|
||||
} else {
|
||||
delete res[k];
|
||||
}
|
||||
} else {
|
||||
res[k] = (obj && obj.toJSON());
|
||||
}
|
||||
});
|
||||
return res;
|
||||
},
|
||||
startNewSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
self.trigger('pgadmin-session:stop', self);
|
||||
self.off('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onChildValid);
|
||||
}
|
||||
|
||||
self.trackChanges = true;
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = _.clone(self.attributes);
|
||||
|
||||
var res = false;
|
||||
|
||||
_.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)) {
|
||||
obj.startNewSession();
|
||||
}
|
||||
});
|
||||
|
||||
// Let people know, I have started session hanlding
|
||||
self.trigger('pgadmin-session:start', self);
|
||||
|
||||
// Let me listen to the my child invalid/valid messages
|
||||
self.on('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.on('pgadmin-session:model:valid', self.onChildValid);
|
||||
|
||||
},
|
||||
onChildInvalid: function(msg, obj) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges && obj) {
|
||||
var objName = obj.attrName;
|
||||
|
||||
if (!objName) {
|
||||
var hasPrimaryKey = obj.primary_key &&
|
||||
typeof(obj.primary_key) === 'function';
|
||||
key = hasPrimaryKey ? obj.primary_key() : obj.cid,
|
||||
comparator = hasPrimaryKey ?
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.primary_key() === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} :
|
||||
function(k) {
|
||||
var o = self.get(k);
|
||||
|
||||
if (o.cid === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
_.findIndex(self.objects, comparator);
|
||||
}
|
||||
|
||||
if (objName && !self.errorModel.has(objName)) {
|
||||
/*
|
||||
* We will trigger error information only once.
|
||||
*/
|
||||
if (!_.size(self.errorModel.attributes)) {
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:invalid', msg, self);
|
||||
} else {
|
||||
self.trigger('pgadmin-session:invalid', msg, self);
|
||||
}
|
||||
}
|
||||
self.errorModel.set(objName, msg);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
onChildValid: function(obj) {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges && obj) {
|
||||
var objName = obj.attrName;
|
||||
|
||||
if (!objName) {
|
||||
var hasPrimaryKey = (obj.primary_key &&
|
||||
(typeof(obj.primary_key) === 'function'));
|
||||
key = hasPrimaryKey ? obj.primary_key() : obj.cid,
|
||||
comparator = hasPrimaryKey ?
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.primary_key() === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} :
|
||||
function(k) {
|
||||
var o = self.get('k');
|
||||
|
||||
if (o && o.cid === key) {
|
||||
objName = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
_.findIndex(self.objects, comparator);
|
||||
}
|
||||
|
||||
if (objName && self.errorModel.has(objName)) {
|
||||
|
||||
self.errorModel.unset(objName);
|
||||
|
||||
/*
|
||||
* We will trigger validation information
|
||||
*/
|
||||
if (_.size(self.errorModel.attributes) == 0) {
|
||||
if (self.handler) {
|
||||
(self.handler).trigger('pgadmin-session:model:valid', self);
|
||||
} else {
|
||||
self.trigger(
|
||||
'pgadmin-session:valid', self.sessChanged(), self
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
stopSession: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.trackChanges) {
|
||||
self.off('pgadmin-session:model:invalid', self.onChildInvalid);
|
||||
self.off('pgadmin-session:model:valid', self.onChildValid);
|
||||
}
|
||||
|
||||
self.trackChanges = false;
|
||||
self.sessAttrs = {};
|
||||
self.origSessAttrs = {};
|
||||
|
||||
_.each(self.objects, function(o) {
|
||||
var obj = self.get(o);
|
||||
|
||||
if (_.isUndefined(obj) || _.isNull(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.origSessAttrs[o] = null;
|
||||
delete self.origSessAttrs[o];
|
||||
|
||||
if (obj && 'stopSession' in obj && _.isFunction(obj.stopSession)) {
|
||||
obj.stopSession();
|
||||
}
|
||||
});
|
||||
|
||||
self.trigger('pgadmin-session:stop');
|
||||
}
|
||||
}),
|
||||
Model: pgBrowser.DataModel,
|
||||
getTreeNodeHierarchy: function(i) {
|
||||
var idx = 0,
|
||||
res = {},
|
||||
|
Loading…
Reference in New Issue
Block a user