mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Introducing the infrastructure for colleciton of the subnodes listing,
creation, and editing within the properties panel infrastructure. We do use the backgrid.js for listing the subnode collection, and for editing/creating new object for the subnode, we do use the same infrastructure using the backform.
This commit is contained in:
parent
c53b57a013
commit
c1503ade47
@ -15,5 +15,7 @@ Require.js 2.1.18 BSD/MIT http://requirejs.org/
|
||||
Underscore.js 1.8.3 MIT http://underscorejs.org/
|
||||
Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/
|
||||
Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform
|
||||
Backbone 1.1.2 MIT http://backbonejs.org
|
||||
font-Awesome 4.3 SIL OFL http://fortawesome.github.io/Font-Awesome/
|
||||
font-mfizz 1.2 MIT http://fizzed.com/oss/font-mfizz
|
||||
backgrid.js 0.3.5 MIT http://backgridjs.com/
|
||||
|
@ -32,8 +32,13 @@ function($, _, pgAdmin, Backbone) {
|
||||
name: null
|
||||
},
|
||||
schema: [
|
||||
{id: 'id', label: 'ID', type: 'int', group: null, mode: ['properties']},
|
||||
{id: 'name', label:'Name', type: 'text', group: null, mode: ['properties', 'edit', 'create']}
|
||||
{
|
||||
id: 'id', label: 'ID', type: 'int', group: null,
|
||||
mode: ['properties']
|
||||
},{
|
||||
id: 'name', label:'Name', type: 'text', group: null,
|
||||
mode: ['properties', 'edit', 'create']
|
||||
}
|
||||
],
|
||||
validate: function(attrs, options) {
|
||||
if (!this.isNew() && 'id' in this.changed) {
|
||||
|
@ -52,8 +52,7 @@ OWNER TO helpdesk;\n';
|
||||
if (d && obj.Nodes[d._type].callbacks['selected'] &&
|
||||
_.isFunction(obj.Nodes[d._type].callbacks['selected'])) {
|
||||
return obj.Nodes[d._type].callbacks['selected'].apply(
|
||||
obj.Nodes[d._type],
|
||||
[{ data: d, browser: obj, item: i }]);
|
||||
obj.Nodes[d._type], [i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -442,10 +441,8 @@ OWNER TO helpdesk;\n';
|
||||
typeof obj.Nodes[d._type].callbacks[eventName] ==
|
||||
'function') {
|
||||
return obj.Nodes[d._type].callbacks[eventName].apply(
|
||||
obj.Nodes[d._type], [{
|
||||
data: d, browser: obj, item: item,
|
||||
eventName: eventName, options: options
|
||||
}]);
|
||||
obj.Nodes[d._type], [item, eventName, options]
|
||||
);
|
||||
}
|
||||
}
|
||||
switch (eventName) {
|
||||
@ -618,7 +615,8 @@ OWNER TO helpdesk;\n';
|
||||
},
|
||||
messages: {
|
||||
'server_lost': '{{ _('Connection to the server has been lost!') }}',
|
||||
'click_for_detailed_msg': '{{ _('%s<br><br>click here for details!') }}'
|
||||
'click_for_detailed_msg': '{{ _('%s<br><br>click here for details!') }}',
|
||||
'general_cateogty': '{{ _('General') }}'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -46,38 +46,6 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
return child;
|
||||
};
|
||||
|
||||
// Defines - which control needs to be instantiated in different modes.
|
||||
// i.e. Node properties, create, edit, etc.
|
||||
var controlType = {
|
||||
'properties': {
|
||||
'int': 'uneditable-input',
|
||||
'text': 'uneditable-input',
|
||||
'numeric': 'uneditable-input',
|
||||
'date': 'date',
|
||||
'boolean': 'bool-text',
|
||||
'options': Backform.ReadonlyOptionControl,
|
||||
'multiline': 'textarea'
|
||||
},
|
||||
'edit': {
|
||||
'int': 'input',
|
||||
'text': 'input',
|
||||
'numeric': 'input',
|
||||
'date': 'date',
|
||||
'boolean': 'boolean',
|
||||
'options': 'select',
|
||||
'multiline': 'textarea'
|
||||
},
|
||||
'create': {
|
||||
'int': 'input',
|
||||
'text': 'input',
|
||||
'numeric': 'input',
|
||||
'date': 'date',
|
||||
'boolean': 'boolean',
|
||||
'options': 'select',
|
||||
'multiline': 'textarea'
|
||||
}
|
||||
};
|
||||
|
||||
_.extend(pgAdmin.Browser.Node, {
|
||||
// Node type
|
||||
type: undefined,
|
||||
@ -115,9 +83,9 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
//
|
||||
// Used to generate view for the particular node properties, edit,
|
||||
// creation.
|
||||
getView: function(type, el, node, formType, callback) {
|
||||
getView: function(type, el, node, formType, callback, data) {
|
||||
|
||||
if (!this.type || this.type == '' || !type in controlType)
|
||||
if (!this.type || this.type == '')
|
||||
// We have no information, how to generate view for this type.
|
||||
return null;
|
||||
|
||||
@ -131,62 +99,25 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
// node.
|
||||
return null;
|
||||
|
||||
var opts = {};
|
||||
var attrs = {};
|
||||
|
||||
// In order to get the object data from the server, we must set
|
||||
// object-id in the model (except in the create mode).
|
||||
if (type !== 'create') {
|
||||
opts[this.model.idAttribute || 'id'] = node._id;
|
||||
attrs[this.model.idAttribute || 'id'] = node._id;
|
||||
}
|
||||
|
||||
// We know - which data model to be used for this object.
|
||||
var newModel = new (this.model.extend({urlRoot: urlBase}))(opts);
|
||||
var newModel = new (this.model.extend({urlRoot: urlBase}))(attrs, {
|
||||
onChangeData: data,
|
||||
onChangeCallback: callback
|
||||
}),
|
||||
groups = Backform.generateViewSchema(newModel, type);
|
||||
|
||||
// 'schema' has the information about how to generate the form.
|
||||
if (newModel.schema && _.isArray(newModel.schema)) {
|
||||
var groups = {};
|
||||
|
||||
_.each(newModel.schema, function(f) {
|
||||
// Do we understand - what control, we're creating
|
||||
// here?
|
||||
if (f && f.mode && _.isObject(f.mode) &&
|
||||
_.indexOf(f.mode, type) != -1 &&
|
||||
type in controlType) {
|
||||
// Each field is kept in specified group, or in
|
||||
// 'General' category.
|
||||
var group = f.group || '{{ _("General") }}';
|
||||
|
||||
// Generate the empty group list (if not exists)
|
||||
if (!groups[group]) {
|
||||
groups[group] = [];
|
||||
}
|
||||
|
||||
// Temporarily store in dictionaly format for
|
||||
// utilizing it later.
|
||||
groups[group].push({
|
||||
name: f.id, label: f.label,
|
||||
control: controlType[type][f.type],
|
||||
// Do we need to show this control in this mode?
|
||||
visible: f.show && newModel[f.show] &&
|
||||
typeof newModel[f.show] == "function" ?
|
||||
newModel[f.show] : f.show,
|
||||
// This can be disabled in some cases (if not hidden)
|
||||
disabled: (type == 'properties' ? true : (
|
||||
f.disabled && newModel[f.disabled] &&
|
||||
typeof newModel[f.disabled] == "function" ?
|
||||
newModel[f.disabled] : undefined)),
|
||||
options: f.options
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Do we have fields to genreate controls, which we
|
||||
// understand?
|
||||
if (_.isEmpty(groups)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (groups) {
|
||||
var fields = [];
|
||||
|
||||
// This will contain the actual view
|
||||
var view;
|
||||
|
||||
@ -214,34 +145,24 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
// This is definetely not in create mode
|
||||
newModel.fetch()
|
||||
.success(function(res, msg, xhr) {
|
||||
if (res) {
|
||||
// We got the latest attributes of the
|
||||
// object. Render the view now.
|
||||
view.render();
|
||||
if (typeof(callback) != "undefined") {
|
||||
callback(view);
|
||||
}
|
||||
}
|
||||
// We got the latest attributes of the
|
||||
// object. Render the view now.
|
||||
view.render();
|
||||
})
|
||||
.error(function(m, jqxhr) {
|
||||
.error(function(jqxhr, error, message) {
|
||||
// TODO:: We may not want to continue from here
|
||||
console.log(arguments);
|
||||
Alertify.pgNotifier(
|
||||
"error", jqxhr,
|
||||
error, jqxhr,
|
||||
S(
|
||||
"{{ _("Error fetching the properties - %%s!") }}"
|
||||
).sprintf(jqxhr.statusText).value()
|
||||
).sprintf(message).value()
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Yay - render the view now!
|
||||
view.render();
|
||||
if (typeof(callback) != "undefined") {
|
||||
callback(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -475,7 +396,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
null).show()
|
||||
},
|
||||
// Callback called - when a node is selected in browser tree.
|
||||
selected: function(o) {
|
||||
selected: function(item) {
|
||||
// Show the information about the selected node in the below panels,
|
||||
// which are visible at this time:
|
||||
// + Properties
|
||||
@ -483,53 +404,54 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
// + Dependents
|
||||
// + Dependencies
|
||||
// + Statistics
|
||||
var b = pgBrowser,
|
||||
t = b.tree,
|
||||
d = t.itemData(item);
|
||||
|
||||
// Update the menu items
|
||||
pgAdmin.Browser.enable_disable_menus.apply(o.browser, [o.item]);
|
||||
pgAdmin.Browser.enable_disable_menus.apply(b, [item]);
|
||||
|
||||
if (o && o.data && o.browser) {
|
||||
var br = o.browser;
|
||||
if ('properties' in br.panels &&
|
||||
br.panels['properties'] &&
|
||||
br.panels['properties'].panel &&
|
||||
br.panels['properties'].panel.isVisible()) {
|
||||
if (d && b) {
|
||||
if ('properties' in b.panels &&
|
||||
b.panels['properties'] &&
|
||||
b.panels['properties'].panel &&
|
||||
b.panels['properties'].panel.isVisible()) {
|
||||
// Show object properties (only when the 'properties' tab
|
||||
// is active).
|
||||
this.showProperties(o.item, o.data,
|
||||
pgBrowser.panels['properties'].panel);
|
||||
this.showProperties(item, d, b.panels['properties'].panel);
|
||||
}
|
||||
if ('sql' in br.panels &&
|
||||
br.panels['sql'] &&
|
||||
br.panels['sql'].panel &&
|
||||
br.panels['sql'].panel.isVisible()) {
|
||||
if ('sql' in b.panels &&
|
||||
b.panels['sql'] &&
|
||||
b.panels['sql'].panel &&
|
||||
b.panels['sql'].panel.isVisible()) {
|
||||
// TODO:: Show reverse engineered query for this object (when 'sql'
|
||||
// tab is active.)
|
||||
}
|
||||
if ('statistics' in br.panels &&
|
||||
br.panels['statistics'] &&
|
||||
br.panels['statistics'].panel &&
|
||||
br.panels['statistics'].panel.isVisible()) {
|
||||
if ('statistics' in b.panels &&
|
||||
b.panels['statistics'] &&
|
||||
b.panels['statistics'].panel &&
|
||||
b.panels['statistics'].panel.isVisible()) {
|
||||
// TODO:: Show statistics for this object (when the 'statistics'
|
||||
// tab is active.)
|
||||
}
|
||||
if ('dependencies' in br.panels &&
|
||||
br.panels['dependencies'] &&
|
||||
br.panels['dependencies'].panel &&
|
||||
br.panels['dependencies'].panel.isVisible()) {
|
||||
if ('dependencies' in b.panels &&
|
||||
b.panels['dependencies'] &&
|
||||
b.panels['dependencies'].panel &&
|
||||
b.panels['dependencies'].panel.isVisible()) {
|
||||
// TODO:: Show dependencies for this object (when the
|
||||
// 'dependencies' tab is active.)
|
||||
}
|
||||
if ('dependents' in br.panels &&
|
||||
br.panels['dependents'] &&
|
||||
br.panels['dependents'].panel &&
|
||||
br.panels['dependents'].panel.isVisible()) {
|
||||
if ('dependents' in b.panels &&
|
||||
b.panels['dependents'] &&
|
||||
b.panels['dependents'].panel &&
|
||||
b.panels['dependents'].panel.isVisible()) {
|
||||
// TODO:: Show dependents for this object (when the 'dependents'
|
||||
// tab is active.)
|
||||
}
|
||||
}
|
||||
},
|
||||
refresh_node: function(args) {
|
||||
this.callbacks.selected();
|
||||
refresh_node: function(item) {
|
||||
this.callbacks.selected(undefined, item);
|
||||
}
|
||||
},
|
||||
/**********************************************************************
|
||||
@ -544,7 +466,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
tree = pgAdmin.Browser.tree,
|
||||
j = panel.$container.find('.obj_properties').first(),
|
||||
view = j.data('obj-view'),
|
||||
content = $('<div></div>')
|
||||
content = $('<div tabindex="1"></div>')
|
||||
.addClass('pg-prop-content col-xs-12'),
|
||||
// Template function to create the button-group
|
||||
createButtons = function(buttons, extraClasses) {
|
||||
@ -644,9 +566,27 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
}
|
||||
// Make sure the HTML element is empty.
|
||||
j.empty();
|
||||
// Create a view to edit/create the properties in fieldsets
|
||||
view = that.getView(action, content, data, 'dialog');
|
||||
|
||||
var modelChanged = function(m, o) {
|
||||
var btnGroup = o.find('.pg-prop-btn-group'),
|
||||
btnSave = btnGroup.find('button[type="save"]'),
|
||||
btnReset = btnGroup.find('button[type="reset"]');
|
||||
|
||||
if (m.sessChanged()) {
|
||||
btnSave.prop('disabled', false);
|
||||
btnSave.removeAttr('disabled');
|
||||
btnReset.prop('disabled', false);
|
||||
btnReset.removeAttr('disabled');
|
||||
} else {
|
||||
btnSave.prop('disabled', true);
|
||||
btnSave.attr('disabled', 'disabled');
|
||||
btnReset.prop('disabled', true);
|
||||
btnReset.attr('disabled', 'disabled');
|
||||
}
|
||||
};
|
||||
|
||||
// Create a view to edit/create the properties in fieldsets
|
||||
view = that.getView(action, content, data, 'dialog', modelChanged, j);
|
||||
if (view) {
|
||||
// Save it to release it later
|
||||
j.data('obj-view', view);
|
||||
@ -659,14 +599,13 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
register: function(btn) {
|
||||
// Save the changes
|
||||
btn.click(function() {
|
||||
|
||||
var m = view.model,
|
||||
c = m.isNew() ? m.attributes :
|
||||
m.changedAttributes();
|
||||
d = m.toJSON(true);
|
||||
|
||||
if (c && !_.isEmpty(c)) {
|
||||
m.save({} ,{
|
||||
attrs: m.attributes,
|
||||
if (d && !_.isEmpty(d)) {
|
||||
m.save({}, {
|
||||
attrs: d,
|
||||
validate: false,
|
||||
success: function() {
|
||||
onSaveFunc.call();
|
||||
},
|
||||
@ -858,14 +797,70 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
||||
return args[arg];
|
||||
});
|
||||
},
|
||||
Collection: Backbone.Collection.extend({
|
||||
}),
|
||||
// Base class for Node Model
|
||||
Model: Backbone.Model.extend({
|
||||
parse: function(res) {
|
||||
var self = this;
|
||||
if ('node' in res && res['node']) {
|
||||
this.tnode = _.extend({}, res.node);
|
||||
self.tnode = _.extend({}, res.node);
|
||||
delete res.node;
|
||||
}
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
if (s.id in res) {
|
||||
var o;
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
o = self.get(s.id)
|
||||
o.reset(res[s.id], [{silent: true}]);
|
||||
res[s.id] = o;
|
||||
break;
|
||||
case 'model':
|
||||
o = self.get(s.id);
|
||||
o.set(res[s.id], [{silent: true}]);
|
||||
res[s.id] = o;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
if (this.schema && _.isArray(this.schema)) {
|
||||
_.each(this.schema, function(s) {
|
||||
var obj = null;
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes) {
|
||||
var node = pgBrowser.Nodes[s.model];
|
||||
obj = new (node.Collection)(null, {model: node.model});
|
||||
} else {
|
||||
obj = new (pgBrowser.Node.Collection)(null, {model: s.model});
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes[s.model]) {
|
||||
obj = new (pgBrowser.Nodes[s.model].Model)(null);
|
||||
} else {
|
||||
obj = new (s.model)(null);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
obj.name = s.id;
|
||||
self.set(s.id, obj, {silent: true});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
240
web/pgadmin/static/css/backgrid/backgrid.css
Normal file
240
web/pgadmin/static/css/backgrid/backgrid.css
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
backgrid
|
||||
http://github.com/wyuenho/backgrid
|
||||
|
||||
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
||||
Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
.backgrid-container {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 465px;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.backgrid {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background-color: transparent;
|
||||
border-collapse: collapse;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.backgrid th,
|
||||
.backgrid td {
|
||||
display: none;
|
||||
height: 20px;
|
||||
max-width: 250px;
|
||||
padding: 4px 5px;
|
||||
overflow: hidden;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
||||
.backgrid th.renderable,
|
||||
.backgrid td.renderable {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.backgrid th {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.backgrid th.sortable a {
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.backgrid thead th {
|
||||
vertical-align: bottom;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.backgrid thead th a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.backgrid.backgrid-striped tbody tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.backgrid tbody tr.empty {
|
||||
font-style: italic;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.backgrid tbody tr.empty td {
|
||||
display: inherit;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.backgrid td.editor {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.backgrid td.editor,
|
||||
.backgrid tbody tr:nth-child(odd) td.editor {
|
||||
background-color: rgba(82, 168, 236, 0.1);
|
||||
outline: 1px solid rgba(82, 168, 236, 0.8);
|
||||
outline-offset: -1px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition-duration: 200ms;
|
||||
-moz-transition-duration: 200ms;
|
||||
-o-transition-duration: 200ms;
|
||||
transition-duration: 200ms;
|
||||
-webkit-transition-property: width, outline, background-color;
|
||||
-moz-transition-property: width, outline, background-color;
|
||||
-o-transition-property: width, outline, background-color;
|
||||
transition-property: width, outline, background-color;
|
||||
-webkit-transition-timing-function: ease-in-out;
|
||||
-moz-transition-timing-function: ease-in-out;
|
||||
-o-transition-timing-function: ease-in-out;
|
||||
transition-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
.backgrid td.editor input[type=text] {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 5px;
|
||||
margin: 0;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
.backgrid td.editor input[type=text]::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.backgrid td.error,
|
||||
.backgrid tbody tr:nth-child(odd) td.error {
|
||||
background-color: rgba(255, 210, 77, 0.1);
|
||||
outline: 1px solid #ffd24d;
|
||||
}
|
||||
|
||||
.backgrid td.editor :focus,
|
||||
.backgrid th.editor :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.backgrid .sort-caret {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 0.3em;
|
||||
border: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.backgrid .ascending .sort-caret {
|
||||
vertical-align: baseline;
|
||||
border-top: none;
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: 4px solid #000000;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
.backgrid .descending .sort-caret {
|
||||
vertical-align: super;
|
||||
border-top: 4px solid #000000;
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: none;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
.backgrid .string-cell,
|
||||
.backgrid .uri-cell,
|
||||
.backgrid .email-cell,
|
||||
.backgrid .string-cell.editor input[type=text],
|
||||
.backgrid .uri-cell.editor input[type=text],
|
||||
.backgrid .email-cell.editor input[type=text] {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.backgrid .date-cell,
|
||||
.backgrid .time-cell,
|
||||
.backgrid .datetime-cell,
|
||||
.backgrid .number-cell,
|
||||
.backgrid .integer-cell,
|
||||
.backgrid .percent-cell,
|
||||
.backgrid .date-cell.editor input[type=text],
|
||||
.backgrid .time-cell.editor input[type=text],
|
||||
.backgrid .datetime-cell.editor input[type=text],
|
||||
.backgrid .number-cell.editor input[type=text],
|
||||
.backgrid .integer-cell.editor input[type=text],
|
||||
.backgrid .percent-cell.editor input[type=text] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.backgrid .boolean-cell,
|
||||
.backgrid .boolean-cell.editor input[type=checkbox] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.backgrid .select-cell {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.backgrid .select-cell.editor {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.backgrid .select-cell.editor select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
padding: 4px 5px;
|
||||
margin: 0;
|
||||
line-height: 28px;
|
||||
vertical-align: middle;
|
||||
background-color: white;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.backgrid .select-cell.editor select[multiple] {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.backgrid .select-cell.editor :focus {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.backgrid .select-cell.editor select::-moz-focus-inner,
|
||||
.backgrid .select-cell.editor optgroup::-moz-focus-inner,
|
||||
.backgrid .select-cell.editor option::-moz-focus-inner,
|
||||
.backgrid .select-cell.editor select::-o-focus-inner,
|
||||
.backgrid .select-cell.editor optgroup::-o-focus-inner,
|
||||
.backgrid .select-cell.editor option::-o-focus-inner {
|
||||
border: 0;
|
||||
}
|
1
web/pgadmin/static/css/backgrid/backgrid.min.css
vendored
Normal file
1
web/pgadmin/static/css/backgrid/backgrid.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.backgrid-container{position:relative;display:block;width:100%;height:465px;padding:0;overflow:auto;border:0}.backgrid{width:100%;max-width:100%;background-color:transparent;border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.backgrid th,.backgrid td{display:none;height:20px;max-width:250px;padding:4px 5px;overflow:hidden;line-height:20px;text-align:left;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;border-bottom:1px solid #DDD}.backgrid th.renderable,.backgrid td.renderable{display:table-cell}.backgrid th{font-weight:bold;text-align:center}.backgrid th.sortable a{text-decoration:none;white-space:nowrap;cursor:pointer}.backgrid thead th{vertical-align:bottom;background-color:#f9f9f9}.backgrid thead th a{display:block}.backgrid.backgrid-striped tbody tr:nth-child(even){background-color:#f9f9f9}.backgrid tbody tr.empty{font-style:italic;color:gray}.backgrid tbody tr.empty td{display:inherit;text-align:center}.backgrid td.editor{padding:0}.backgrid td.editor,.backgrid tbody tr:nth-child(odd) td.editor{background-color:rgba(82,168,236,0.1);outline:1px solid rgba(82,168,236,0.8);outline-offset:-1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition-duration:200ms;-moz-transition-duration:200ms;-o-transition-duration:200ms;transition-duration:200ms;-webkit-transition-property:width,outline,background-color;-moz-transition-property:width,outline,background-color;-o-transition-property:width,outline,background-color;transition-property:width,outline,background-color;-webkit-transition-timing-function:ease-in-out;-moz-transition-timing-function:ease-in-out;-o-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out}.backgrid td.editor input[type=text]{display:block;width:100%;height:100%;padding:0 5px;margin:0;background-color:transparent;border:0;outline:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none}.backgrid td.editor input[type=text]::-ms-clear{display:none}.backgrid td.error,.backgrid tbody tr:nth-child(odd) td.error{background-color:rgba(255,210,77,0.1);outline:1px solid #ffd24d}.backgrid td.editor :focus,.backgrid th.editor:focus{outline:0}.backgrid .sort-caret{display:inline-block;width:0;height:0;margin-left:.3em;border:0;content:""}.backgrid .ascending .sort-caret{vertical-align:baseline;border-top:0;border-right:4px solid transparent;border-bottom:4px solid #000;border-left:4px solid transparent}.backgrid .descending .sort-caret{vertical-align:super;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0;border-left:4px solid transparent}.backgrid .string-cell,.backgrid .uri-cell,.backgrid .email-cell,.backgrid .string-cell.editor input[type=text],.backgrid .uri-cell.editor input[type=text],.backgrid .email-cell.editor input[type=text]{text-align:left}.backgrid .date-cell,.backgrid .time-cell,.backgrid .datetime-cell,.backgrid .number-cell,.backgrid .integer-cell,.backgrid .percent-cell,.backgrid .date-cell.editor input[type=text],.backgrid .time-cell.editor input[type=text],.backgrid .datetime-cell.editor input[type=text],.backgrid .number-cell.editor input[type=text],.backgrid .integer-cell.editor input[type=text],.backgrid .percent-cell.editor input[type=text]{text-align:right}.backgrid .boolean-cell,.backgrid .boolean-cell.editor input[type=checkbox]{text-align:center}.backgrid .select-cell{text-align:center}.backgrid .select-cell.editor{padding:0}.backgrid .select-cell.editor select{display:block;width:100%;height:28px;padding:4px 5px;margin:0;line-height:28px;vertical-align:middle;background-color:white;border:0;outline:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.backgrid .select-cell.editor select[multiple]{height:auto}.backgrid .select-cell.editor :focus{border:0;outline:0}.backgrid .select-cell.editor select::-moz-focus-inner,.backgrid .select-cell.editor optgroup::-moz-focus-inner,.backgrid .select-cell.editor option::-moz-focus-inner,.backgrid .select-cell.editor select::-o-focus-inner,.backgrid .select-cell.editor optgroup::-o-focus-inner,.backgrid .select-cell.editor option::-o-focus-inner{border:0}
|
924
web/pgadmin/static/css/bootstrap-datepicker3.css
vendored
924
web/pgadmin/static/css/bootstrap-datepicker3.css
vendored
File diff suppressed because it is too large
Load Diff
8
web/pgadmin/static/css/bootstrap-datepicker3.min.css
vendored
Normal file
8
web/pgadmin/static/css/bootstrap-datepicker3.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -382,7 +382,7 @@ iframe {
|
||||
}
|
||||
|
||||
.pg-prop-btn-group button:not(:first-child):not(:last-child) {
|
||||
margin: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.pg-prop-content {
|
||||
@ -448,3 +448,116 @@ fieldset[disabled] .form-control {
|
||||
margin-left: -18px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
|
||||
|
||||
/* Sub-Node */
|
||||
|
||||
.table-bordered > thead > tr > td, .table-bordered > thead > tr > th {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.subnode > table.backgrid{
|
||||
width: 99%;
|
||||
margin: 0.1% 0.49%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.backgrid thead th{
|
||||
background-color: #2c76b4;
|
||||
}
|
||||
|
||||
.backgrid th, .backgrid td {
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.backgrid td {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.backgrid thead th a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.backgrid > th.object {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.edit-cell, .delete-cell {
|
||||
text-align:center !important;
|
||||
width:25px;
|
||||
}
|
||||
|
||||
.backgrid td.renderable:not(.editable):not(.delete-cell) {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.subnode-header {
|
||||
background-color:#2c76b4;
|
||||
height:35px;
|
||||
color:#FFFFFF;
|
||||
border-radius:5px 5px 0px 0px;
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
.subnode-header > button.add {
|
||||
float:right;
|
||||
margin-right:15px;
|
||||
}
|
||||
|
||||
.subnode {
|
||||
margin-top:5px;
|
||||
padding-top:0px;
|
||||
border-left:1px solid #dadada;
|
||||
border-bottom:1px solid #ddd;
|
||||
border-right:1px solid #ddd;
|
||||
}
|
||||
|
||||
.subnode-dialog {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
right: 0;
|
||||
height:auto;
|
||||
margin-left: 23px;
|
||||
background-color: #dadada;
|
||||
margin-top: 0px;
|
||||
border: 1px solid #a9a9a9;
|
||||
}
|
||||
.subnode-body {
|
||||
height:auto;
|
||||
overflow:inherit;
|
||||
|
||||
}
|
||||
.subnode-footer {
|
||||
height:38px;;
|
||||
margin: 0px, 15px;
|
||||
min-height:40px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.sub-node-form {
|
||||
height:auto;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.sub-node-form > .nav-tabs {
|
||||
background-color: #DADADA;
|
||||
}
|
||||
|
||||
.sub-node-form > ul.tab-content{
|
||||
background-color: #FFFFFF;
|
||||
padding-left: 15px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
table.backgrid tr.new {
|
||||
background-color: rgba(82, 168, 236, 0.1) !important;
|
||||
box-sizing: border-box;
|
||||
outline: 1px solid rgba(82, 168, 236, 0.8);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
@ -10,10 +10,11 @@
|
||||
|
||||
// Set up Backform appropriately for the environment. Start with AMD.
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['underscore', 'jquery', 'backbone', 'backform'], function(_, $, Backbone, Backform) {
|
||||
define(['underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'pgadmin.backgrid'],
|
||||
function(_, $, Backbone, Backform, Backgrid) {
|
||||
// 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);
|
||||
return factory(root, _, $, Backbone, Backform, Backgrid);
|
||||
});
|
||||
|
||||
// Next for Node.js or CommonJS. jQuery may not be needed as a module.
|
||||
@ -21,14 +22,16 @@
|
||||
var _ = require('underscore') || root._,
|
||||
$ = root.jQuery || root.$ || root.Zepto || root.ender,
|
||||
Backbone = require('backbone') || root.Backbone,
|
||||
Backform = require('backform') || root.Backform;
|
||||
factory(root, _, $, Backbone, Backform);
|
||||
Backform = require('backform') || root.Backform,
|
||||
Backgrid = require('backgrid') || root.Backgrid;
|
||||
pgAdminBackgrid = require('pgadmin.backgrid');
|
||||
factory(root, _, $, Backbone, Backform, Backgrid);
|
||||
|
||||
// Finally, as a browser global.
|
||||
} else {
|
||||
factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform);
|
||||
factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.Backgrid);
|
||||
}
|
||||
}(this, function(root, _, $, Backbone, Backform) {
|
||||
}(this, function(root, _, $, Backbone, Backform, Backgrid) {
|
||||
|
||||
// HTML markup global class names. More can be added by individual controls
|
||||
// using _.extend. Look at RadioControl as an example.
|
||||
@ -41,6 +44,51 @@
|
||||
setGroupContentClassName: "fieldset-content col-xs-12"
|
||||
});
|
||||
|
||||
var controlMapper = Backform.controlMapper = {
|
||||
'int': ['uneditable-input', 'input', 'integer'],
|
||||
'text': ['uneditable-input', 'input', 'string'],
|
||||
'numeric': ['uneditable-input', 'input', 'number'],
|
||||
'date': 'datepicker',
|
||||
'boolean': 'boolean',
|
||||
'options': ['readonly-option', 'select', Backgrid.Extension.PGSelectCell],
|
||||
'multiline': ['textarea', 'textarea', 'string'],
|
||||
'collection': ['sub-node-collection', 'sub-node-collection', 'string']
|
||||
};
|
||||
|
||||
var getMappedControl = Backform.getMappedControl = function(type, mode) {
|
||||
if (type in Backform.controlMapper) {
|
||||
var m = Backform.controlMapper[type];
|
||||
|
||||
if (!_.isArray(m)) {
|
||||
return m;
|
||||
}
|
||||
|
||||
var idx = 1, len = _.size(m);
|
||||
|
||||
switch (mode) {
|
||||
case 'properties':
|
||||
idx = 0;
|
||||
break;
|
||||
case 'edit':
|
||||
case 'create':
|
||||
case 'control':
|
||||
idx = 1;
|
||||
break;
|
||||
case 'cell':
|
||||
idx = 2;
|
||||
break;
|
||||
default:
|
||||
idx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return m[idx > len ? 0 : idx];
|
||||
}
|
||||
alert ("Developer: did you forget to put/implement the control type - '" + type + "' in mapper");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Override the Backform.Control to allow to track changes in dependencies,
|
||||
// and rerender the View element
|
||||
var BackformControlInit = Backform.Control.prototype.initialize;
|
||||
@ -72,7 +120,7 @@
|
||||
'<div class="<%=Backform.controlsClassName%>">',
|
||||
'<% for (var i=0; i < options.length; i++) { %>',
|
||||
' <% var option = options[i]; %>',
|
||||
' <% if (option.value === rawValue) { %>',
|
||||
' <% if (option.value === rawValue) { %>',
|
||||
' <span class="<%=Backform.controlClassName%> uneditable-input" disabled><%-option.label%></span>',
|
||||
' <% } %>',
|
||||
'<% } %>',
|
||||
@ -214,5 +262,196 @@
|
||||
events: {}
|
||||
});
|
||||
|
||||
var SubNodeCollectionControl = Backform.SubNodeCollectionControl = Backform.Control.extend({
|
||||
render: function() {
|
||||
var field = _.defaults(this.field.toJSON(), this.defaults),
|
||||
attributes = this.model.toJSON(),
|
||||
attrArr = field.name.split('.'),
|
||||
name = attrArr.shift(),
|
||||
path = attrArr.join('.'),
|
||||
rawValue = this.keyPathAccessor(attributes[name], path),
|
||||
data = _.extend(field, {
|
||||
rawValue: rawValue,
|
||||
value: this.formatter.fromRaw(rawValue, this.model),
|
||||
attributes: attributes,
|
||||
formatter: this.formatter
|
||||
}),
|
||||
evalF = function(f, m) {
|
||||
return (_.isFunction(f) ? !!f(m) : !!f);
|
||||
};
|
||||
|
||||
// Evaluate the disabled, visible, required, canAdd, cannEdit & canDelete option
|
||||
_.extend(data, {
|
||||
disabled: evalF(data.disabled, this.model),
|
||||
visible: evalF(data.visible, this.model),
|
||||
required: evalF(data.required, this.model),
|
||||
canAdd: evalF(data.canAdd, this.model),
|
||||
canEdit: evalF(data.canEdit, this.model),
|
||||
canDelete: evalF(data.canDelete, this.model)
|
||||
});
|
||||
// Show Backgrid Control
|
||||
grid = (data.subnode == undefined) ? "" : this.showGridControl(data);
|
||||
|
||||
this.$el.html(grid).addClass(field.name);
|
||||
this.updateInvalid();
|
||||
|
||||
return this;
|
||||
},
|
||||
showGridControl: function(data) {
|
||||
var gridHeader = ["<div class='subnode-header'>",
|
||||
" <label class='control-label col-sm-4'>" + data.label + "</label>" ,
|
||||
" <button class='btn-sm btn-default add'>Add</buttton>",
|
||||
"</div>"].join("\n");
|
||||
gridBody = $("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode' >").append(gridHeader);
|
||||
|
||||
var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
|
||||
columns = [],
|
||||
gridColumns = [],
|
||||
groups = Backform.generateViewSchema(subnode, this.field.get('mode')),
|
||||
schema = [];
|
||||
|
||||
// Prepare columns for backgrid
|
||||
_.each(groups, function(fields, key) {
|
||||
_.each(fields, function(f) {
|
||||
if (!f.control && !f.cell) {
|
||||
return;
|
||||
}
|
||||
f.cel_priority = _.indexOf(data.columns, f.name);
|
||||
if (f.cel_priority != -1) {
|
||||
columns.push(f);
|
||||
}
|
||||
});
|
||||
schema.push({label: key, fields: fields});
|
||||
});
|
||||
|
||||
// Set visibility of Add button
|
||||
if (data.disabled || data.canAdd == false) {
|
||||
$(gridBody).find("button.add").remove();
|
||||
}
|
||||
|
||||
// Insert Delete Cell into Grid
|
||||
if (data.disabled == false && data.canDelete) {
|
||||
columns.unshift({
|
||||
name: "pg-backform-delete", label: "",
|
||||
cell: Backgrid.Extension.DeleteCell,
|
||||
editable: false, priority: -1
|
||||
});
|
||||
}
|
||||
|
||||
// Insert Edit Cell into Grid
|
||||
if (data.disabled == false && data.canEdit) {
|
||||
var editCell = Backgrid.Extension.ObjectCell.extend({
|
||||
schema: schema
|
||||
});
|
||||
|
||||
columns.unshift({
|
||||
name: "pg-backform-edit", label: "", cell : editCell,
|
||||
priority: -2
|
||||
});
|
||||
}
|
||||
|
||||
var collections = this.model.get(data.name);
|
||||
|
||||
// Initialize a new Grid instance
|
||||
var grid = new Backgrid.Grid({
|
||||
columns: _.sortBy(columns, function(c) { return c.cell_priority; }),
|
||||
collection: collections,
|
||||
className: "backgrid table-bordered"
|
||||
});
|
||||
|
||||
// Render subNode grid
|
||||
subNodeGrid = grid.render().$el;
|
||||
|
||||
// Combine Edit and Delete Cell
|
||||
if (data.canDelete && data.canEdit) {
|
||||
$(subNodeGrid).find("th.pg-backform-delete").remove();
|
||||
$(subNodeGrid).find("th.pg-backform-edit").attr("colspan", "2");
|
||||
}
|
||||
|
||||
$dialog = gridBody.append(subNodeGrid);
|
||||
|
||||
// Add button callback
|
||||
$dialog.find('button.add').click(function(e) {
|
||||
e.preventDefault();
|
||||
grid.insertRow({});
|
||||
newRow = $(grid.body.rows[collections.length - 1].$el);
|
||||
newRow.attr("class", "new").click(function(e) {
|
||||
$(this).attr("class", "");
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
});
|
||||
|
||||
///////
|
||||
// Generate a schema (as group members) based on the model's schema
|
||||
//
|
||||
// It will be used by the grid, properties, and dialog view generation
|
||||
// functions.
|
||||
var generateViewSchema = Backform.generateViewSchema = function(Model, mode) {
|
||||
var proto = (Model && Model.prototype) || Model,
|
||||
schema = (proto && proto.schema),
|
||||
groups, pgBrowser = window.pgAdmin.Browser;
|
||||
|
||||
// 'schema' has the information about how to generate the form.
|
||||
if (schema && _.isArray(schema)) {
|
||||
var evalASFunc = evalASFunc = function(prop) {
|
||||
return ((prop && proto[prop] &&
|
||||
typeof proto[prop] == "function") ? proto[prop] : prop);
|
||||
};
|
||||
groups = {};
|
||||
|
||||
_.each(schema, function(s) {
|
||||
// Do we understand - what control, we're creating
|
||||
// here?
|
||||
if (!s.mode || (s && s.mode && _.isObject(s.mode) &&
|
||||
_.indexOf(s.mode, mode) != -1)) {
|
||||
// Each field is kept in specified group, or in
|
||||
// 'General' category.
|
||||
var group = s.group || pgBrowser.messages.general_cateogty,
|
||||
control = Backform.getMappedControl(s.type, mode),
|
||||
cell = s.cell || Backform.getMappedControl(s.type, 'cell');
|
||||
|
||||
if (control == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the empty group list (if not exists)
|
||||
groups[group] = (groups[group] || []);
|
||||
|
||||
var o = _.extend(_.clone(s), {
|
||||
name: s.id,
|
||||
// Do we need to show this control in this mode?
|
||||
visible: evalASFunc(s.show),
|
||||
// This can be disabled in some cases (if not hidden)
|
||||
disabled: (mode == 'properties' ? true : evalASFunc(s.disabled)),
|
||||
subnode: (_.isString(s.model) && s.model in pgBrowser.Nodes) ?
|
||||
pgBrowser.Nodes[s.model].model : s.model,
|
||||
canAdd: (mode == 'properties' ? false : evalASFunc(s.canAdd)),
|
||||
canEdit: (mode == 'properties' ? false : evalASFunc(s.canEdit)),
|
||||
canDelete: (mode == 'properties' ? false : evalASFunc(s.canDelete)),
|
||||
mode: mode,
|
||||
control: control,
|
||||
cell: cell
|
||||
});
|
||||
delete o.id;
|
||||
|
||||
// Temporarily store in dictionaly format for
|
||||
// utilizing it later.
|
||||
groups[group].push(o);
|
||||
}
|
||||
});
|
||||
|
||||
// Do we have fields to genreate controls, which we
|
||||
// understand?
|
||||
if (_.isEmpty(groups)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
return Backform;
|
||||
}));
|
||||
|
2883
web/pgadmin/static/js/backgrid/backgrid.js
Normal file
2883
web/pgadmin/static/js/backgrid/backgrid.js
Normal file
File diff suppressed because it is too large
Load Diff
8
web/pgadmin/static/js/backgrid/backgrid.min.js
vendored
Normal file
8
web/pgadmin/static/js/backgrid/backgrid.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
234
web/pgadmin/static/js/backgrid/backgrid.pgadmin.js
Normal file
234
web/pgadmin/static/js/backgrid/backgrid.pgadmin.js
Normal file
@ -0,0 +1,234 @@
|
||||
(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'],
|
||||
function(_, $, Backbone, Backform, Backgrid, Alertify) {
|
||||
// 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);
|
||||
});
|
||||
|
||||
// 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;
|
||||
factory(root, _, $, Backbone, Backform, Alertify);
|
||||
|
||||
// Finally, as a browser global.
|
||||
} else {
|
||||
factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform);
|
||||
}
|
||||
} (this, function(root, _, $, Backbone, Backform, Alertify) {
|
||||
var ObjectCellEditor = Backgrid.Extension.ObjectCellEditor = Backgrid.CellEditor.extend({
|
||||
modalTemplate: _.template([
|
||||
'<div class="subnode-dialog">',
|
||||
' <div class="subnode-body"></div>',
|
||||
' <div class="subnode-footer">',
|
||||
' <button style ="float:right;margin-right:15px;margin-top: 4px;" class="cancel btn btn-danger" type="cancel">Cancel</button>',
|
||||
' <button style ="float:right;margin-right:10px;margin-top: 4px;" class="save btn btn-primary" type="save">Save</button>',
|
||||
' </div>',
|
||||
'</div>'
|
||||
].join("\n")),
|
||||
stringTemplate: _.template([
|
||||
'<div class="form-group">',
|
||||
' <label class="control-label col-sm-4"><%=label%></label>',
|
||||
' <div class="col-sm-8">',
|
||||
' <input type="text" class="form-control" name="<%=name%>" value="<%=value%>" placeholder="<%=placeholder%>" />',
|
||||
' </div>',
|
||||
'</div>'
|
||||
].join("\n")),
|
||||
|
||||
extendWithOptions: function(options) {
|
||||
_.extend(this, options);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return this;
|
||||
},
|
||||
postRender: function(model, column) {
|
||||
var editor = this,
|
||||
el = this.el;
|
||||
columns_length = this.columns_length;
|
||||
|
||||
if (column != null && column.get("name") != this.column.get("name"))
|
||||
return false;
|
||||
|
||||
if (!_.isArray(this.schema)) throw new TypeError("schema must be an array");
|
||||
|
||||
// Create a Backbone model from our object if it does not exist
|
||||
if (!this.origModel) {
|
||||
this.origModel = this.model;
|
||||
this.model = this.origModel.clone();
|
||||
}
|
||||
|
||||
var $dialog = this.createDialog(columns_length);
|
||||
|
||||
// Add the Bootstrap form
|
||||
var $form = $('<form class="form-dialog"></form>');
|
||||
$dialog.find('div.subnode-body').append($form);
|
||||
|
||||
// Call Backform to prepare dialog
|
||||
back_el = $dialog.find('form.form-dialog');
|
||||
Backform.tabClassName = "sub-node-form col-sm-12";
|
||||
|
||||
objectView = new Backform.Dialog({
|
||||
el: back_el, model: this.model, schema: this.schema,
|
||||
});
|
||||
|
||||
objectView.render();
|
||||
|
||||
return this;
|
||||
},
|
||||
createDialog: function(noofcol) {
|
||||
var editor1 = this,
|
||||
$dialog = this.$dialog = $(this.modalTemplate({title: ""})),
|
||||
tr = $("<tr>"),
|
||||
td = $("<td>", {class: 'editable sortable renderable', style: 'height: auto', colspan: noofcol+2}).appendTo(tr);
|
||||
|
||||
noofcol = noofcol || 1;
|
||||
// Handle close and save events
|
||||
$dialog.find('button.cancel').click(function(e) {
|
||||
e.preventDefault();
|
||||
editor1.cancel();
|
||||
tr.remove();
|
||||
return false;
|
||||
});
|
||||
$dialog.find('button.save').click(function(e) {
|
||||
e.preventDefault();
|
||||
editor1.save();
|
||||
tr.remove();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Show the Bootstrap modal dialog
|
||||
td.append($dialog.css('display', 'block'));
|
||||
this.el.parent('tr').after(tr);
|
||||
|
||||
return $dialog;
|
||||
},
|
||||
save: function(options) {
|
||||
options || (options = {});
|
||||
var model = this.origModel,
|
||||
column = this.column,
|
||||
objectModel = this.model,
|
||||
$form = this.$dialog.find('form');
|
||||
|
||||
// Retrieve values from the form, and store inside the object model
|
||||
var changes = {};
|
||||
_.each(this.schema, function(field) {
|
||||
inputType = (field.control == 'datepicker' ? 'input' : field.control);
|
||||
val = $form.find(inputType + '[name='+field.name+']').first().val()
|
||||
val = (field.cell == 'integer') ? parseInt(val) :
|
||||
(field.cell == 'number') ? parseFloat(val) : val
|
||||
|
||||
changes[field.name] = val;
|
||||
});
|
||||
|
||||
objectModel.set(changes);
|
||||
model.set(changes, options);
|
||||
|
||||
model.trigger("backgrid:edited", model, column, new Backgrid.Command({keyCode:13}));
|
||||
|
||||
return this;
|
||||
},
|
||||
cancel: function() {
|
||||
this.origModel.trigger("backgrid:edited", this.origModel, this.column, new Backgrid.Command({keyCode:27}));
|
||||
return this;
|
||||
},
|
||||
remove: function() {
|
||||
this.$dialog.modal("hide").remove();
|
||||
Backgrid.CellEditor.prototype.remove.apply(this, arguments);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
var PGSelectCell = Backgrid.Extension.PGSelectCell = Backgrid.SelectCell.extend({
|
||||
// It's possible to render an option group or use a
|
||||
// function to provide option values too.
|
||||
optionValues: function() {
|
||||
var res = [];
|
||||
opts = _.result(this.column.attributes, 'options');
|
||||
_.each(opts, function(o) {
|
||||
res.push([o.label, o.value]);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
var ObjectCell = Backgrid.Extension.ObjectCell = Backgrid.Cell.extend({
|
||||
editorOptionDefaults: {
|
||||
schema: []
|
||||
},
|
||||
className: "edit-cell",
|
||||
editor: ObjectCellEditor,
|
||||
initialize: function(options) {
|
||||
Backgrid.Cell.prototype.initialize.apply(this, arguments);
|
||||
|
||||
// Pass on cell options to the editor
|
||||
var cell = this,
|
||||
editorOptions = {};
|
||||
_.each(this.editorOptionDefaults, function(def, opt) {
|
||||
if (!cell[opt]) cell[opt] = def;
|
||||
if (options && options[opt]) cell[opt] = options[opt];
|
||||
editorOptions[opt] = cell[opt];
|
||||
});
|
||||
|
||||
editorOptions['el'] = $(this.el);
|
||||
editorOptions['columns_length'] = this.column.collection.length
|
||||
|
||||
this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
|
||||
if (column.get("name") == this.column.get("name"))
|
||||
editor.extendWithOptions(editorOptions);
|
||||
});
|
||||
},
|
||||
enterEditMode: function () {
|
||||
var $content = this.$el.html();
|
||||
Backgrid.Cell.prototype.enterEditMode.apply(this, arguments);
|
||||
var editable = Backgrid.callByNeed(this.column.editable(), this.column, this.model);
|
||||
if (editable) this.$el.html("<i class='fa fa-minus-square-o'></i>");
|
||||
},
|
||||
render: function(){
|
||||
this.$el.empty();
|
||||
this.$el.html("<i class='fa fa-pencil-square-o'></i>");
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
var DeleteCell = Backgrid.Extension.DeleteCell = Backgrid.Cell.extend({
|
||||
/** @property */
|
||||
className: "delete-cell",
|
||||
events: {
|
||||
"click": "deleteRow"
|
||||
},
|
||||
deleteRow: function (e) {
|
||||
e.preventDefault();
|
||||
that = this;
|
||||
Alertify.confirm(
|
||||
'Delete Row',
|
||||
'Are You Sure, you want to delete this object?',
|
||||
function(evt) {
|
||||
that.model.collection.remove(that.model);
|
||||
},
|
||||
function(evt) {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
},
|
||||
initialize: function () {
|
||||
Backgrid.Cell.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.$el.html("<i class='fa fa-trash'></i>");
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
return Backgrid;
|
||||
|
||||
}));
|
205
web/pgadmin/static/js/bootstrap-datepicker.js
vendored
205
web/pgadmin/static/js/bootstrap-datepicker.js
vendored
@ -1,10 +1,18 @@
|
||||
/*!
|
||||
* Datepicker for Bootstrap v1.5.0-dev (https://github.com/eternicode/bootstrap-datepicker)
|
||||
* Datepicker for Bootstrap v1.5.0 (https://github.com/eternicode/bootstrap-datepicker)
|
||||
*
|
||||
* Copyright 2012 Stefan Petre
|
||||
* Improvements by Andrew Rowls
|
||||
* Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
*/(function($, undefined){
|
||||
*/(function(factory){
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["jquery"], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function($, undefined){
|
||||
|
||||
function UTCDate(){
|
||||
return new Date(Date.UTC.apply(Date, arguments));
|
||||
@ -25,6 +33,9 @@
|
||||
return this[method].apply(this, arguments);
|
||||
};
|
||||
}
|
||||
function isValidDate(d) {
|
||||
return d && !isNaN(d.getTime());
|
||||
}
|
||||
|
||||
var DateArray = (function(){
|
||||
var extras = {
|
||||
@ -115,6 +126,7 @@
|
||||
this.setStartDate(this._o.startDate);
|
||||
this.setEndDate(this._o.endDate);
|
||||
this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
|
||||
this.setDaysOfWeekHighlighted(this.o.daysOfWeekHighlighted);
|
||||
this.setDatesDisabled(this.o.datesDisabled);
|
||||
|
||||
this.fillDow();
|
||||
@ -175,6 +187,20 @@
|
||||
o.minViewMode = 0;
|
||||
}
|
||||
|
||||
switch (o.maxViewMode) {
|
||||
case 0:
|
||||
case 'days':
|
||||
o.maxViewMode = 0;
|
||||
break;
|
||||
case 1:
|
||||
case 'months':
|
||||
o.maxViewMode = 1;
|
||||
break;
|
||||
default:
|
||||
o.maxViewMode = 2;
|
||||
}
|
||||
|
||||
o.startView = Math.min(o.startView, o.maxViewMode);
|
||||
o.startView = Math.max(o.startView, o.minViewMode);
|
||||
|
||||
// true, false, or Number > 0
|
||||
@ -219,6 +245,13 @@
|
||||
return parseInt(d, 10);
|
||||
});
|
||||
|
||||
o.daysOfWeekHighlighted = o.daysOfWeekHighlighted||[];
|
||||
if (!$.isArray(o.daysOfWeekHighlighted))
|
||||
o.daysOfWeekHighlighted = o.daysOfWeekHighlighted.split(/[,\s]*/);
|
||||
o.daysOfWeekHighlighted = $.map(o.daysOfWeekHighlighted, function(d){
|
||||
return parseInt(d, 10);
|
||||
});
|
||||
|
||||
o.datesDisabled = o.datesDisabled||[];
|
||||
if (!$.isArray(o.datesDisabled)) {
|
||||
var datesDisabled = [];
|
||||
@ -269,6 +302,7 @@
|
||||
o.defaultViewDate = UTCToday();
|
||||
}
|
||||
o.showOnFocus = o.showOnFocus !== undefined ? o.showOnFocus : true;
|
||||
o.zIndexOffset = o.zIndexOffset !== undefined ? o.zIndexOffset : 10;
|
||||
},
|
||||
_events: [],
|
||||
_secondaryEvents: [],
|
||||
@ -376,9 +410,10 @@
|
||||
this.element.is(e.target) ||
|
||||
this.element.find(e.target).length ||
|
||||
this.picker.is(e.target) ||
|
||||
this.picker.find(e.target).length
|
||||
this.picker.find(e.target).length ||
|
||||
this.picker.hasClass('datepicker-inline')
|
||||
)){
|
||||
$(this.picker).hide();
|
||||
this.hide();
|
||||
}
|
||||
}, this)
|
||||
}]
|
||||
@ -534,7 +569,7 @@
|
||||
}
|
||||
|
||||
if (element) {
|
||||
element.val('').change();
|
||||
element.val('');
|
||||
}
|
||||
|
||||
this.update();
|
||||
@ -567,11 +602,11 @@
|
||||
var formatted = this.getFormattedDate();
|
||||
if (!this.isInput){
|
||||
if (this.component){
|
||||
this.element.find('input').val(formatted).change();
|
||||
this.element.find('input').val(formatted);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.element.val(formatted).change();
|
||||
this.element.val(formatted);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
@ -607,6 +642,12 @@
|
||||
return this;
|
||||
},
|
||||
|
||||
setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
|
||||
this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
|
||||
this.update();
|
||||
return this;
|
||||
},
|
||||
|
||||
setDatesDisabled: function(datesDisabled){
|
||||
this._process_options({datesDisabled: datesDisabled});
|
||||
this.update();
|
||||
@ -619,17 +660,17 @@
|
||||
var calendarWidth = this.picker.outerWidth(),
|
||||
calendarHeight = this.picker.outerHeight(),
|
||||
visualPadding = 10,
|
||||
windowWidth = $(this.o.container).width(),
|
||||
windowHeight = $(this.o.container).height(),
|
||||
scrollTop = $(this.o.container).scrollTop(),
|
||||
appendOffset = $(this.o.container).offset();
|
||||
container = $(this.o.container),
|
||||
windowWidth = container.width(),
|
||||
scrollTop = container.scrollTop(),
|
||||
appendOffset = container.offset();
|
||||
|
||||
var parentsZindex = [];
|
||||
this.element.parents().each(function(){
|
||||
var itemZIndex = $(this).css('z-index');
|
||||
if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
|
||||
});
|
||||
var zIndex = Math.max.apply(Math, parentsZindex) + 10;
|
||||
var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
|
||||
var offset = this.component ? this.component.parent().offset() : this.element.offset();
|
||||
var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
|
||||
var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
|
||||
@ -666,20 +707,17 @@
|
||||
// auto y orientation is best-situation: top or bottom, no fudging,
|
||||
// decision based on which shows more of the calendar
|
||||
var yorient = this.o.orientation.y,
|
||||
top_overflow, bottom_overflow;
|
||||
top_overflow;
|
||||
if (yorient === 'auto'){
|
||||
top_overflow = -scrollTop + top - calendarHeight;
|
||||
bottom_overflow = scrollTop + windowHeight - (top + height + calendarHeight);
|
||||
if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
|
||||
yorient = 'top';
|
||||
else
|
||||
yorient = 'bottom';
|
||||
yorient = top_overflow < 0 ? 'bottom' : 'top';
|
||||
}
|
||||
|
||||
this.picker.addClass('datepicker-orient-' + yorient);
|
||||
if (yorient === 'top')
|
||||
top += height;
|
||||
else
|
||||
top -= calendarHeight + parseInt(this.picker.css('padding-top'));
|
||||
else
|
||||
top += height;
|
||||
|
||||
if (this.o.rtl) {
|
||||
var right = windowWidth - (left + width);
|
||||
@ -743,6 +781,8 @@
|
||||
this.viewDate = new Date(this.o.startDate);
|
||||
else if (this.viewDate > this.o.endDate)
|
||||
this.viewDate = new Date(this.o.endDate);
|
||||
else
|
||||
this.viewDate = this.o.defaultViewDate;
|
||||
|
||||
if (fromArgs){
|
||||
// setting date by clicking
|
||||
@ -757,6 +797,7 @@
|
||||
this._trigger('clearDate');
|
||||
|
||||
this.fill();
|
||||
this.element.change();
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -764,12 +805,11 @@
|
||||
var dowCnt = this.o.weekStart,
|
||||
html = '<tr>';
|
||||
if (this.o.calendarWeeks){
|
||||
this.picker.find('.datepicker-days thead tr:first-child .datepicker-switch')
|
||||
this.picker.find('.datepicker-days .datepicker-switch')
|
||||
.attr('colspan', function(i, val){
|
||||
return parseInt(val) + 1;
|
||||
});
|
||||
var cell = '<th class="cw"> </th>';
|
||||
html += cell;
|
||||
html += '<th class="cw"> </th>';
|
||||
}
|
||||
while (dowCnt < this.o.weekStart + 7){
|
||||
html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
|
||||
@ -823,6 +863,9 @@
|
||||
$.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){
|
||||
cls.push('disabled');
|
||||
}
|
||||
if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
|
||||
cls.push('highlighted');
|
||||
}
|
||||
if (this.o.datesDisabled.length > 0 &&
|
||||
$.grep(this.o.datesDisabled, function(d){
|
||||
return isUTCEquals(date, d); }).length > 0) {
|
||||
@ -836,6 +879,12 @@
|
||||
if ($.inArray(date.valueOf(), this.range) !== -1){
|
||||
cls.push('selected');
|
||||
}
|
||||
if (date.valueOf() === this.range[0]){
|
||||
cls.push('range-start');
|
||||
}
|
||||
if (date.valueOf() === this.range[this.range.length-1]){
|
||||
cls.push('range-end');
|
||||
}
|
||||
}
|
||||
return cls;
|
||||
},
|
||||
@ -850,17 +899,21 @@
|
||||
endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
|
||||
todaytxt = dates[this.o.language].today || dates['en'].today || '',
|
||||
cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
|
||||
titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
|
||||
tooltip;
|
||||
if (isNaN(year) || isNaN(month))
|
||||
return;
|
||||
this.picker.find('.datepicker-days thead .datepicker-switch')
|
||||
.text(dates[this.o.language].months[month]+' '+year);
|
||||
.text(DPGlobal.formatDate(new UTCDate(year, month), titleFormat, this.o.language));
|
||||
this.picker.find('tfoot .today')
|
||||
.text(todaytxt)
|
||||
.toggle(this.o.todayBtn !== false);
|
||||
this.picker.find('tfoot .clear')
|
||||
.text(cleartxt)
|
||||
.toggle(this.o.clearBtn !== false);
|
||||
this.picker.find('thead .datepicker-title')
|
||||
.text(this.o.title)
|
||||
.toggle(this.o.title !== '');
|
||||
this.updateNavArrows();
|
||||
this.fillMonths();
|
||||
var prevMonth = UTCDate(year, month-1, 28),
|
||||
@ -868,6 +921,9 @@
|
||||
prevMonth.setUTCDate(day);
|
||||
prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
|
||||
var nextMonth = new Date(prevMonth);
|
||||
if (prevMonth.getUTCFullYear() < 100){
|
||||
nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
|
||||
}
|
||||
nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
|
||||
nextMonth = nextMonth.valueOf();
|
||||
var html = [];
|
||||
@ -921,8 +977,8 @@
|
||||
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
|
||||
|
||||
var months = this.picker.find('.datepicker-months')
|
||||
.find('th:eq(1)')
|
||||
.text(year)
|
||||
.find('.datepicker-switch')
|
||||
.text(this.o.maxViewMode < 2 ? 'Months' : year)
|
||||
.end()
|
||||
.find('span').removeClass('active');
|
||||
|
||||
@ -956,7 +1012,7 @@
|
||||
html = '';
|
||||
year = parseInt(year/10, 10) * 10;
|
||||
var yearCont = this.picker.find('.datepicker-years')
|
||||
.find('th:eq(1)')
|
||||
.find('.datepicker-switch')
|
||||
.text(year + '-' + (year + 9))
|
||||
.end()
|
||||
.find('td');
|
||||
@ -967,6 +1023,8 @@
|
||||
classes;
|
||||
for (var i = -1; i < 11; i++){
|
||||
classes = ['year'];
|
||||
tooltip = null;
|
||||
|
||||
if (i === -1)
|
||||
classes.push('old');
|
||||
else if (i === 10)
|
||||
@ -975,7 +1033,24 @@
|
||||
classes.push('active');
|
||||
if (year < startYear || year > endYear)
|
||||
classes.push('disabled');
|
||||
html += '<span class="' + classes.join(' ') + '">' + year + '</span>';
|
||||
|
||||
if (this.o.beforeShowYear !== $.noop) {
|
||||
var yrBefore = this.o.beforeShowYear(new Date(year, 0, 1));
|
||||
if (yrBefore === undefined)
|
||||
yrBefore = {};
|
||||
else if (typeof(yrBefore) === 'boolean')
|
||||
yrBefore = {enabled: yrBefore};
|
||||
else if (typeof(yrBefore) === 'string')
|
||||
yrBefore = {classes: yrBefore};
|
||||
if (yrBefore.enabled === false)
|
||||
classes.push('disabled');
|
||||
if (yrBefore.classes)
|
||||
classes = classes.concat(yrBefore.classes.split(/\s+/));
|
||||
if (yrBefore.tooltip)
|
||||
tooltip = yrBefore.tooltip;
|
||||
}
|
||||
|
||||
html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>' + year + '</span>';
|
||||
year += 1;
|
||||
}
|
||||
yearCont.html(html);
|
||||
@ -1005,13 +1080,13 @@
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){
|
||||
if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() || this.o.maxViewMode < 2){
|
||||
this.picker.find('.prev').css({visibility: 'hidden'});
|
||||
}
|
||||
else {
|
||||
this.picker.find('.prev').css({visibility: 'visible'});
|
||||
}
|
||||
if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){
|
||||
if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() || this.o.maxViewMode < 2){
|
||||
this.picker.find('.next').css({visibility: 'hidden'});
|
||||
}
|
||||
else {
|
||||
@ -1023,6 +1098,7 @@
|
||||
|
||||
click: function(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var target = $(e.target).closest('span, td, th'),
|
||||
year, month, day;
|
||||
if (target.length === 1){
|
||||
@ -1176,8 +1252,8 @@
|
||||
},
|
||||
|
||||
moveMonth: function(date, dir){
|
||||
if (!date)
|
||||
return undefined;
|
||||
if (!isValidDate(date))
|
||||
return this.o.defaultViewDate;
|
||||
if (!dir)
|
||||
return date;
|
||||
var new_date = new Date(date.valueOf()),
|
||||
@ -1235,8 +1311,10 @@
|
||||
|
||||
keydown: function(e){
|
||||
if (!this.picker.is(':visible')){
|
||||
if (e.keyCode === 40 || e.keyCode === 27) // allow down to re-show picker
|
||||
if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
|
||||
this.show();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var dateChanged = false,
|
||||
@ -1252,6 +1330,7 @@
|
||||
else
|
||||
this.hide();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
break;
|
||||
case 37: // left
|
||||
case 39: // right
|
||||
@ -1314,6 +1393,9 @@
|
||||
// As such, its behavior should not be hijacked.
|
||||
break;
|
||||
case 13: // enter
|
||||
if (!this.o.forceParse) {
|
||||
break;
|
||||
}
|
||||
focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
|
||||
if (this.o.keyboardNavigation) {
|
||||
this._toggle_multidate(focusDate);
|
||||
@ -1361,13 +1443,13 @@
|
||||
|
||||
showMode: function(dir){
|
||||
if (dir){
|
||||
this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
|
||||
this.viewMode = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, this.viewMode + dir));
|
||||
}
|
||||
this.picker
|
||||
.children('div')
|
||||
.hide()
|
||||
.filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName)
|
||||
.css('display', 'block');
|
||||
.show();
|
||||
this.updateNavArrows();
|
||||
}
|
||||
};
|
||||
@ -1410,8 +1492,13 @@
|
||||
return;
|
||||
this.updating = true;
|
||||
|
||||
var dp = $(e.target).data('datepicker'),
|
||||
new_date = dp.getUTCDate(),
|
||||
var dp = $(e.target).data('datepicker');
|
||||
|
||||
if (typeof(dp) === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
var new_date = dp.getUTCDate(),
|
||||
i = $.inArray(e.target, this.inputs),
|
||||
j = i - 1,
|
||||
k = i + 1,
|
||||
@ -1509,14 +1596,20 @@
|
||||
}
|
||||
if (typeof option === 'string' && typeof data[option] === 'function'){
|
||||
internal_return = data[option].apply(data, args);
|
||||
if (internal_return !== undefined)
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (internal_return !== undefined)
|
||||
return internal_return;
|
||||
else
|
||||
|
||||
if (
|
||||
internal_return === undefined ||
|
||||
internal_return instanceof Datepicker ||
|
||||
internal_return instanceof DateRangePicker
|
||||
)
|
||||
return this;
|
||||
|
||||
if (this.length > 1)
|
||||
throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
|
||||
else
|
||||
return internal_return;
|
||||
};
|
||||
$.fn.datepicker = datepickerPlugin;
|
||||
|
||||
@ -1524,10 +1617,12 @@
|
||||
autoclose: false,
|
||||
beforeShowDay: $.noop,
|
||||
beforeShowMonth: $.noop,
|
||||
beforeShowYear: $.noop,
|
||||
calendarWeeks: false,
|
||||
clearBtn: false,
|
||||
toggleActive: false,
|
||||
daysOfWeekDisabled: [],
|
||||
daysOfWeekHighlighted: [],
|
||||
datesDisabled: [],
|
||||
endDate: Infinity,
|
||||
forceParse: true,
|
||||
@ -1535,6 +1630,7 @@
|
||||
keyboardNavigation: true,
|
||||
language: 'en',
|
||||
minViewMode: 0,
|
||||
maxViewMode: 2,
|
||||
multidate: false,
|
||||
multidateSeparator: ',',
|
||||
orientation: "auto",
|
||||
@ -1547,7 +1643,8 @@
|
||||
disableTouchKeyboard: false,
|
||||
enableOnReadonly: true,
|
||||
container: 'body',
|
||||
immediateUpdates: false
|
||||
immediateUpdates: false,
|
||||
title: ''
|
||||
};
|
||||
var locale_opts = $.fn.datepicker.locale_opts = [
|
||||
'format',
|
||||
@ -1563,7 +1660,8 @@
|
||||
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
||||
today: "Today",
|
||||
clear: "Clear"
|
||||
clear: "Clear",
|
||||
titleFormat: "MM yyyy"
|
||||
}
|
||||
};
|
||||
|
||||
@ -1593,7 +1691,9 @@
|
||||
validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
|
||||
nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
|
||||
parseFormat: function(format){
|
||||
// IE treats \0 as a string end in inputs (truncating the value),
|
||||
if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
|
||||
return format;
|
||||
// IE treats \0 as a string end in inputs (truncating the value),
|
||||
// so it's a bad format delimiter, anyway
|
||||
var separators = format.replace(this.validParts, '\0').split('\0'),
|
||||
parts = format.match(this.validParts);
|
||||
@ -1609,7 +1709,9 @@
|
||||
return date;
|
||||
if (typeof format === 'string')
|
||||
format = DPGlobal.parseFormat(format);
|
||||
var part_re = /([\-+]\d+)([dmwy])/,
|
||||
if (format.toValue)
|
||||
return format.toValue(date, format, language);
|
||||
var part_re = /([\-+]\d+)([dmwy])/,
|
||||
parts = date.match(/([\-+]\d+)([dmwy])/g),
|
||||
part, dir, i;
|
||||
if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
|
||||
@ -1714,7 +1816,9 @@
|
||||
return '';
|
||||
if (typeof format === 'string')
|
||||
format = DPGlobal.parseFormat(format);
|
||||
var val = {
|
||||
if (format.toDisplay)
|
||||
return format.toDisplay(date, format, language);
|
||||
var val = {
|
||||
d: date.getUTCDate(),
|
||||
D: dates[language].daysShort[date.getUTCDay()],
|
||||
DD: dates[language].days[date.getUTCDay()],
|
||||
@ -1736,6 +1840,9 @@
|
||||
return date.join('');
|
||||
},
|
||||
headTemplate: '<thead>'+
|
||||
'<tr>'+
|
||||
'<th colspan="7" class="datepicker-title"></th>'+
|
||||
'</tr>'+
|
||||
'<tr>'+
|
||||
'<th class="prev">«</th>'+
|
||||
'<th colspan="5" class="datepicker-switch"></th>'+
|
||||
@ -1789,7 +1896,7 @@
|
||||
|
||||
/* DATEPICKER VERSION
|
||||
* =================== */
|
||||
$.fn.datepicker.version = "1.4.1-dev";
|
||||
$.fn.datepicker.version = '1.5.0';
|
||||
|
||||
/* DATEPICKER DATA-API
|
||||
* ================== */
|
||||
@ -1810,4 +1917,4 @@
|
||||
datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
|
||||
});
|
||||
|
||||
}(window.jQuery));
|
||||
}));
|
||||
|
File diff suppressed because one or more lines are too long
@ -22,6 +22,7 @@
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/font-awesome.css' if config.DEBUG else 'css/font-awesome.min.css') }}"/>
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/font-mfizz.css') }}"/>
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-datepicker3.css')}}"/>
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/backgrid/backgrid.css')}}"/>
|
||||
|
||||
<!-- View specified stylesheets -->
|
||||
{% for stylesheet in current_app.stylesheets %}
|
||||
@ -44,9 +45,19 @@
|
||||
"bootstrap": {
|
||||
"deps": ['jquery'],
|
||||
},
|
||||
"backgrid": {
|
||||
"deps": ['backform'],
|
||||
"exports": 'Backgrid',
|
||||
},
|
||||
"bootstrap.datepicker": {
|
||||
"deps": ['jquery', 'bootstrap'],
|
||||
"exports": 'jQuery.fn.datepicker'
|
||||
},
|
||||
"pgadmin.backgrid": {
|
||||
"deps": ["backgrid", "bootstrap.datepicker"],
|
||||
},
|
||||
"pgadmin.backform": {
|
||||
"deps": ['backform', "pgadmin.backgrid"],
|
||||
}{% for script in current_app.javascripts %}{% if 'deps' in script or 'exports' in script %},
|
||||
'{{ script.name }}': {
|
||||
{% if 'deps' in script %}"deps": [ {% set comma = False %}{% for dep in script['deps'] %} {% if comma %},{% else %}{% set comma = True %}{% endif %} '{{ dep }}'{% endfor %}],{% endif %}
|
||||
@ -65,6 +76,8 @@
|
||||
backbone: "{{ url_for('static', filename='js/' + ('backbone' if config.DEBUG else 'backbone-min')) }}",
|
||||
"bootstrap.datepicker": "{{ url_for('static', filename='js/' + ('bootstrap-datepicker' if config.DEBUG else 'bootstrap-datepicker.min')) }}",
|
||||
backform: "{{ url_for('static', filename='js/backform') }}",
|
||||
backgrid: "{{ url_for('static', filename='js/backgrid/' + ('backgrid' if config.DEBUG else 'backgrid.min')) }}",
|
||||
"pgadmin.backgrid": "{{ url_for('static', filename='js/backgrid/backgrid.pgadmin') }}",
|
||||
'pgadmin.backform': "{{ url_for('static', filename='js/backform.pgadmin') }}"{% for script in current_app.javascripts %},
|
||||
'{{ script.name }}': "{{ script.path }}"{% endfor %}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user