Added undo action on some of the UI changes too.
i.e. Switch between the tabs, opening/closing the subnode in edit mode. Also, removed the Save, Cancel buttons from the subnode editor, it was looking very redudant. Ctrl+Z for undo, Ctrl+Shift+Z/Ctrl+Y for Redo shortcut will be good enough for undoing all the changes in the properties panel.pull/3/head
parent
6c62d9eecd
commit
30c560f33b
|
@ -658,7 +658,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
// Register the Ctrl/Meta+Z -> for Undo operation
|
||||
// and Ctrl+Shift+Z/Ctrl+Y -> Redo operation in the edit/create
|
||||
// dialog.
|
||||
content.on('keydown', function(e) {
|
||||
content.closest('.wcFrame').attr('tabindex', "1").on('keydown', function(e) {
|
||||
switch (e.keyCode) {
|
||||
case 90:
|
||||
if ((e['ctrlKey'] || e['metaKey'])) {
|
||||
|
@ -849,6 +849,79 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
self.handler.undoMgr.merge(self.undoMgr);
|
||||
}
|
||||
|
||||
self.undoMgr.addUndoType("pg-sub-node:opened", {
|
||||
"on": function (model, cell) {
|
||||
return {
|
||||
"object": cell,
|
||||
"before": null,
|
||||
"after": null
|
||||
}
|
||||
},
|
||||
"undo": function (cell, before, after, opts) {
|
||||
if (cell && cell.exitEditMode &&
|
||||
_.isFunction(cell.exitEditMode)) {
|
||||
cell.exitEditMode();
|
||||
}
|
||||
},
|
||||
"redo": function (cell, before, after, opts) {
|
||||
if (cell && cell.enterEditMode &&
|
||||
_.isFunction(cell.enterEditMode)) {
|
||||
cell.enterEditMode();
|
||||
}
|
||||
}
|
||||
});
|
||||
self.undoMgr.addUndoType("pg-sub-node:closed", {
|
||||
"on": function (cell, index) {
|
||||
return {
|
||||
"object": cell,
|
||||
"before": null,
|
||||
"after": null,
|
||||
"options": index
|
||||
}
|
||||
},
|
||||
"undo": function (cell, before, after, opts) {
|
||||
if (cell && cell.enterEditMode &&
|
||||
_.isFunction(cell.enterEditMode)) {
|
||||
cell.enterEditMode();
|
||||
cell.currentEditor.objectView.$el
|
||||
.find('.nav-tabs').first()
|
||||
.find('a[data-tab-index="' + opts + '"]').tab('show');
|
||||
}
|
||||
},
|
||||
"redo": function (cell, before, after, opts) {
|
||||
if (cell && cell.exitEditMode &&
|
||||
_.isFunction(cell.exitEditMode)) {
|
||||
cell.exitEditMode();
|
||||
}
|
||||
}
|
||||
});
|
||||
self.undoMgr.addUndoType("pg-property-tab-changed", {
|
||||
"ignore": false,
|
||||
'mgr': self.undoMgr,
|
||||
"on": function (tabs) {
|
||||
if (!this.ignore && !this.mgr.stack.isCurrentlyUndoRedoing) {
|
||||
return {
|
||||
"object": tabs,
|
||||
"before": null,
|
||||
"after": null,
|
||||
"options": this
|
||||
}
|
||||
}
|
||||
this.igonre = false;
|
||||
},
|
||||
"undo": function (obj, before, after, opts) {
|
||||
if (obj.hidden) {
|
||||
opts.ignore = true;
|
||||
$(obj.hidden).tab('show');
|
||||
}
|
||||
},
|
||||
"redo": function (obj, before, after, opts) {
|
||||
if (obj.shown) {
|
||||
opts.ignore = true;
|
||||
$(obj.shown).tab('show');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.on('add', self.onModelAdd);
|
||||
self.on('remove', self.onModelRemove);
|
||||
|
|
|
@ -142,6 +142,9 @@
|
|||
className: function() {
|
||||
return 'col-sm-12 col-md-12 col-lg-12 col-xs-12';
|
||||
},
|
||||
tabPanelClassName: function() {
|
||||
return Backform.tabClassName;
|
||||
},
|
||||
initialize: function(opts) {
|
||||
var s = opts.schema;
|
||||
if (s && _.isArray(s)) {
|
||||
|
@ -152,6 +155,9 @@
|
|||
o.hId = o.hId || _.uniqueId('pgH_');
|
||||
o.disabled = o.disabled || false;
|
||||
});
|
||||
if (opts.tabPanelClassName && _.isFunction(opts.tabPanelClassName)) {
|
||||
this.tabPanelClassName = opts.tabPanelClassName;
|
||||
}
|
||||
}
|
||||
this.model.errorModel = opts.errorModel || this.model.errorModel || new Backbone.Model();
|
||||
this.controls = [];
|
||||
|
@ -159,7 +165,7 @@
|
|||
template: {
|
||||
'header': _.template([
|
||||
'<li role="presentation" <%=disabled ? "disabled" : ""%>>',
|
||||
' <a data-toggle="tab" href="#<%=cId%>"',
|
||||
' <a data-toggle="tab" data-tab-index="<%=tabIndex%>" href="#<%=cId%>"',
|
||||
' id="<%=hId%>" aria-controls="<%=cId%>">',
|
||||
'<%=label%></a></li>'].join(" ")),
|
||||
'panel': _.template(
|
||||
|
@ -173,12 +179,14 @@
|
|||
.first().attr('id'),
|
||||
m = this.model,
|
||||
controls = this.controls,
|
||||
tmpls = this.template;
|
||||
tmpls = this.template,
|
||||
self = this,
|
||||
idx=0;
|
||||
|
||||
this.$el
|
||||
.empty()
|
||||
.attr('role', 'tabpanel')
|
||||
.attr('class', Backform.tabClassName);
|
||||
.attr('class', this.tabPanelClassName());
|
||||
|
||||
var tabHead = $('<ul class="nav nav-tabs" role="tablist"></ul>')
|
||||
.appendTo(this.$el);
|
||||
|
@ -186,7 +194,7 @@
|
|||
.appendTo(this.$el);
|
||||
|
||||
_.each(this.schema, function(o) {
|
||||
var el = $((tmpls['panel'])(o))
|
||||
var el = $((tmpls['panel'])(_.extend(o, {'tabIndex': idx++})))
|
||||
.appendTo(tabContent)
|
||||
.removeClass('collapse').addClass('collapse'),
|
||||
h = $((tmpls['header'])(o)).appendTo(tabHead);
|
||||
|
@ -199,6 +207,14 @@
|
|||
el.append(cntr.render().$el);
|
||||
controls.push(cntr);
|
||||
});
|
||||
tabHead.find('a[data-toggle="tab"]').on('hidden.bs.tab', function() {
|
||||
self.hidden_tab = this;
|
||||
});
|
||||
tabHead.find('a[data-toggle="tab"]').on('shown.bs.tab', function() {
|
||||
self.shown_tab = this;
|
||||
self.curr_tab_index = $(this).data('tabIndex');
|
||||
m.trigger('pg-property-tab-changed', {'shown': self.shown_tab, 'hidden': self.hidden_tab});
|
||||
});
|
||||
});
|
||||
|
||||
var makeActive = tabHead.find('[id="' + c + '"]').first();
|
||||
|
@ -302,7 +318,7 @@
|
|||
" <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);
|
||||
gridBody = $("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode'></div>").append(gridHeader);
|
||||
|
||||
var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
|
||||
columns = [],
|
||||
|
|
|
@ -24,12 +24,8 @@
|
|||
} (this, function(root, _, $, Backbone, Backform, Alertify) {
|
||||
var ObjectCellEditor = Backgrid.Extension.ObjectCellEditor = Backgrid.CellEditor.extend({
|
||||
modalTemplate: _.template([
|
||||
'<div class="subnode-dialog">',
|
||||
'<div class="subnode-dialog" tabindex="1">',
|
||||
' <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([
|
||||
|
@ -40,11 +36,9 @@
|
|||
' </div>',
|
||||
'</div>'
|
||||
].join("\n")),
|
||||
|
||||
extendWithOptions: function(options) {
|
||||
_.extend(this, options);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return this;
|
||||
},
|
||||
|
@ -59,11 +53,6 @@
|
|||
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
|
||||
|
@ -72,36 +61,25 @@
|
|||
|
||||
// Call Backform to prepare dialog
|
||||
back_el = $dialog.find('form.form-dialog');
|
||||
Backform.tabClassName = "sub-node-form col-sm-12";
|
||||
|
||||
objectView = new Backform.Dialog({
|
||||
this.objectView = new Backform.Dialog({
|
||||
el: back_el, model: this.model, schema: this.schema,
|
||||
tabPanelClassName: function() {
|
||||
return 'sub-node-form col-sm-12';
|
||||
}
|
||||
});
|
||||
|
||||
objectView.render();
|
||||
this.objectView.render();
|
||||
|
||||
return this;
|
||||
},
|
||||
createDialog: function(noofcol) {
|
||||
var editor1 = this,
|
||||
$dialog = this.$dialog = $(this.modalTemplate({title: ""})),
|
||||
var $dialog = this.$dialog = $(this.modalTemplate({title: ""})),
|
||||
tr = $("<tr>"),
|
||||
noofcol = noofcol || 1,
|
||||
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;
|
||||
});
|
||||
this.tr = tr;
|
||||
|
||||
// Show the Bootstrap modal dialog
|
||||
td.append($dialog.css('display', 'block'));
|
||||
|
@ -109,38 +87,21 @@
|
|||
|
||||
return $dialog;
|
||||
},
|
||||
save: function(options) {
|
||||
options || (options = {});
|
||||
var model = this.origModel,
|
||||
column = this.column,
|
||||
objectModel = this.model,
|
||||
$form = this.$dialog.find('form');
|
||||
|
||||
save: function() {
|
||||
// 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
|
||||
this.model.trigger("backgrid:edited", this.model, this.column, new Backgrid.Command({keyCode:13}));
|
||||
if (this.tr) {
|
||||
this.tr.remove();
|
||||
}
|
||||
|
||||
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);
|
||||
if (this.tr) {
|
||||
this.tr.remove();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
@ -177,7 +138,7 @@
|
|||
});
|
||||
|
||||
editorOptions['el'] = $(this.el);
|
||||
editorOptions['columns_length'] = this.column.collection.length
|
||||
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"))
|
||||
|
@ -185,16 +146,45 @@
|
|||
});
|
||||
},
|
||||
enterEditMode: function () {
|
||||
var $content = this.$el.html();
|
||||
Backgrid.Cell.prototype.enterEditMode.apply(this, arguments);
|
||||
/* Make sure - we listen to the click event */
|
||||
this.delegateEvents();
|
||||
var editable = Backgrid.callByNeed(this.column.editable(), this.column, this.model);
|
||||
if (editable) this.$el.html("<i class='fa fa-minus-square-o'></i>");
|
||||
if (editable) {
|
||||
this.$el.html(
|
||||
"<i class='fa fa-pencil-square subnode-edit-in-process'></i>"
|
||||
);
|
||||
this.model.trigger(
|
||||
"pg-sub-node:opened", this.model, this
|
||||
);
|
||||
}
|
||||
},
|
||||
render: function(){
|
||||
this.$el.empty();
|
||||
this.$el.html("<i class='fa fa-pencil-square-o'></i>");
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
exitEditMode: function() {
|
||||
var index = $(this.currentEditor.objectView.el)
|
||||
.find('.nav-tabs > .active > a[data-toggle="tab"]').first()
|
||||
.data('tabIndex');
|
||||
Backgrid.Cell.prototype.exitEditMode.apply(this, arguments);
|
||||
this.model.trigger(
|
||||
"pg-sub-node:closed", this, index
|
||||
);
|
||||
},
|
||||
events: {
|
||||
'click': function(e) {
|
||||
if (this.$el.find('i').first().hasClass('subnode-edit-in-process')) {
|
||||
// Need to redundantly undelegate events for Firefox
|
||||
this.undelegateEvents();
|
||||
this.currentEditor.save();
|
||||
} else {
|
||||
this.enterEditMode.call(this, []);
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue