Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Don't allow users to edit anything if there's no editable layer visible #65

Merged
merged 12 commits into from
Mar 28, 2012
Merged
129 changes: 105 additions & 24 deletions core/src/script/CGXP/plugins/Editing.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
*/
win: null,

/** private: property[newFeatureBtn]
* ``Ext.form.SplitButton``
* The 'create an new feature' button.
*/
newFeatureBtn: null,

/** api: config[helpText]
* ``String``
* The text to the top of the editing window (i18n).
Expand All @@ -110,6 +116,12 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
*/
createBtnText: 'Create a new feature',

/** private: config[pendingRequests]
* ``GeoExt.data.AttributeStore``
* The list of pendingRequests (actually the attribute stores)
*/
pendingRequests: null,

/** private: method[init]
*/
init: function() {
Expand All @@ -118,24 +130,80 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
this.map = this.target.mapPanel.map;
this.addEditingLayer();
this.createGetFeatureControl();
this.pendingRequests = [];

this.newFeatureBtn = this.createNewFeatureBtn();
var win = this.win = new Ext.Window({
width: 300,
border: false,
closable: false,
plain: true,
resizable: false,
disabled: true,
items: [{
xtype: 'box',
html: this.helpText + '<hr />'
}, this.createNewFeatureBtn()]
}, this.newFeatureBtn]
});
this.target.mapPanel.on({
'render': function() {
win.show();
win.anchorTo.defer(100, win, [this.body, 'tl-tl', [55, 10]]);
}
});

var portal = this.target;
portal.on({
ready: function() {
var tree = portal.tools[this.layerTreeId].tree;
tree.on({
checkchange: this.manageLayers,
addgroup: this.manageLayers,
removegroup: this.manageLayers,
scope: this
});
},
scope: this
});
},

/** private: manageLayers
* Checks if there are editable layers, enables or disables the editing
* window and updates the editable layers list in the create new feature
* button.
*/
manageLayers: function() {
var layers = this.getEditableLayers();
var size = 0;
var menu = this.newFeatureBtn.menu;
this.abortPendingRequests();
var alreadyAvailableItems = [];
menu.items.each(function(item) {
if (!item.layerId) {
return;
}
// remove items that are not in the layers list anymore
if (!layers[item.layerId]) {
menu.remove(item);
} else {
alreadyAvailableItems.push(item.layerId);
}
});
for (var i in layers) {
size++;
// only add an item for new editable layers
if (alreadyAvailableItems.indexOf(i) == -1) {
this.getAttributesStore(layers[i].attributes.layer_id, null, (function(store, geometryType, layer) {
menu.add(this.createMenuItem(layer, geometryType));
}).createDelegate(this, [layers[i]], true));
}
}
this.win.setDisabled(size === 0);
if (size === 0) {
this.newFeatureBtn.toggle(false);
this.newFeatureBtn.setText(this.createBtnText);
this.closeEditing();
}
},

/** private: method[addEditingLayer]
Expand Down Expand Up @@ -165,30 +233,24 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
/** private: method[createNewFeatureBtn]
*/
createNewFeatureBtn: function() {
function manageMenuItems() {
menu.removeAll();
menu.add('<b class="menu-title">' + this.layerMenuText + '</b>');
var layers = this.getEditableLayers();
for (var i in layers) {
this.getAttributesStore(layers[i].attributes.layer_id, null, function(store, geometryType) {
menu.add(this.createMenuItem(layers[i], geometryType));
});
var menu = new Ext.menu.Menu({
items: ['<b class="menu-title">' + this.layerMenuText + '</b>'],
listeners: {
beforeremove: function(menu, item) {
if (newFeatureBtn.activeItem == item) {
newFeatureBtn.toggle(false);
newFeatureBtn.activeItem = null;
newFeatureBtn.setText(newFeatureBtn.initialConfig.text);
}
if (this.editorGrid &&
this.editorGrid.store.feature.attributes.__layer_id__.toString() == item.layerId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think toString isn't necessary.

this.closeEditing();
}
},
scope: this
}
}

var portal = this.target;
portal.on({
ready: function() {
var tree = portal.tools[this.layerTreeId].tree;
tree.on({
addgroup: manageMenuItems.createDelegate(this),
removegroup: manageMenuItems.createDelegate(this)
});
},
scope: this
});

var menu = new Ext.menu.Menu({});
window.menu = menu;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be removed.

var newFeatureBtn = new Ext.SplitButton({
text: this.createBtnText,
enableToggle: true,
Expand Down Expand Up @@ -235,7 +297,7 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
this.editingLayer, Handler, {
featureAdded: OpenLayers.Function.bind(function(f) {
control.deactivate();
newFeatureBtn.toggle(false);
this.newFeatureBtn.toggle(false);
f.attributes.__layer_id__ =
layer.attributes.layer_id;
var store = this.getAttributesStore(
Expand All @@ -256,6 +318,7 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
text: layer.attributes.text,
group: 'create_layer',
enableToggle: true,
layerId: layer.attributes.layer_id.toString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is toString necessary here?

control: control,
listeners: {
checkchange: function(item, checked) {
Expand Down Expand Up @@ -318,6 +381,9 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
for (var i in self.getEditableLayers()) {
layerIds.push(i);
}
if (layerIds.length === 0) {
return;
}
options.url = baseURL + layerIds.join(',');
// ensure that there's no unsaved modification before sending
// the request.
Expand Down Expand Up @@ -387,12 +453,27 @@ cgxp.plugins.Editing = Ext.extend(gxp.plugins.Tool, {
});
callback.call(this, store, geometryType);
},
beforeload: function(store) {
this.pendingRequests.push(store);
},
scope: this
});
store.load();
return store;
},

/** private: method[abortPendingRequests]
* This method aborts xsd request if required.
*/
abortPendingRequests: function() {
Ext.each(this.pendingRequests, function(store) {
// destroying the store will destroy the corresponding proxy, and
// the corresponding active requests
store.destroy();
});
this.pendingRequests = [];
},

/** private: method[showAttributesEditingWindow]
*/
showAttributesEditingWindow: function(store) {
Expand Down
88 changes: 88 additions & 0 deletions core/tests/spec/script/CGXP/plugins/Editing.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,92 @@ describe('plugins.Editing', function() {
expect(item.control.handler.multi).toBeTruthy();
});
});
describe('when calling init', function() {
beforeEach(function() {
var map = new OpenLayers.Map();
e = new cgxp.plugins.Editing({
layersURL: '/layers/',
map: map
});
e.init({
tools: {},
on: function() {},
mapPanel: {
on: function() {},
map: map
}
});
});
it('sets the editing plugin window to disabled', function() {
expect(e.win.disabled).toBeTruthy();
});
});
describe('when list of editable layers changes', function() {
var server,
clock,
map = new OpenLayers.Map();
beforeEach(function() {
server = sinon.fakeServer.create();
clock = sinon.useFakeTimers();
e = new cgxp.plugins.Editing({
layersURL: '/layers/',
map: map
});
e.init({
tools: {},
on: function() {},
mapPanel: {
on: function() {},
map: map
}
});
e.getEditableLayers = function() {
return layers;
};
e.getAttributesStore = function() {};
});
afterEach(function() {
server.restore();
clock.restore();
});
var layers;
it('sets the editing plugin window to enabled', function() {
layers = {
'l3': {
attributes: 'bar'
}
};
e.manageLayers();
expect(e.win.disabled).toBeFalsy();
});

it('sends requests with getFeature control', function() {
var oldRead = OpenLayers.Protocol.HTTP.prototype.read;
var foo = false;
OpenLayers.Protocol.HTTP.prototype.read = function() {
foo = true;
};

map.getControlsByClass('OpenLayers.Control.GetFeature')[0].request();
OpenLayers.Protocol.HTTP.prototype.read = oldRead;
expect(foo).toBeTruthy();
});

it('sets the editing plugin window to disabled', function() {
layers = {};
e.manageLayers();
expect(e.win.disabled).toBeTruthy();
});
it('prevents requests with getFeature control to be sent', function() {
var oldRead = OpenLayers.Protocol.HTTP.prototype.read;
var foo = false;
OpenLayers.Protocol.HTTP.prototype.read = function() {
foo = true;
};

map.getControlsByClass('OpenLayers.Control.GetFeature')[0].request();
OpenLayers.Protocol.HTTP.prototype.read = oldRead;
expect(foo).toBeFalsy();
});
});
});