diff --git a/core/js/systemtags/systemtagsinputfield.js b/core/js/systemtags/systemtagsinputfield.js index b90ecbe426..ae9f93ca67 100644 --- a/core/js/systemtags/systemtagsinputfield.js +++ b/core/js/systemtags/systemtagsinputfield.js @@ -186,6 +186,12 @@ return false; }, + _addToSelect2Selection: function(selection) { + var data = this.$tagsField.select2('data'); + data.push(selection); + this.$tagsField.select2('data', data); + }, + /** * Event handler whenever a tag is selected. * Also called whenever tag creation is requested through the dummy tag object. @@ -204,10 +210,27 @@ userAssignable: true }, { success: function(model) { - var data = self.$tagsField.select2('data'); - data.push(model.toJSON()); - self.$tagsField.select2('data', data); + self._addToSelect2Selection(model.toJSON()); self.trigger('select', model); + }, + error: function(model, xhr) { + if (xhr.status === 409) { + // re-fetch collection to get the missing tag + self.collection.reset(); + self.collection.fetch({ + success: function(collection) { + // find the tag in the collection + var model = collection.where({name: e.object.name, userVisible: true, userAssignable: true}); + if (model.length) { + model = model[0]; + // the tag already exists or was already assigned, + // add it to the list anyway + self._addToSelect2Selection(model.toJSON()); + self.trigger('select', model); + } + } + }); + } } }); this.$tagsField.select2('close'); diff --git a/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js b/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js index 07e926cd2a..0ad383860b 100644 --- a/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js +++ b/core/js/tests/specs/systemtags/systemtagsinputfieldSpec.js @@ -158,6 +158,65 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() { expect(selectHandler.calledOnce).toEqual(true); expect(selectHandler.getCall(0).args[0]).toEqual('2'); }); + it('triggers select event and still adds to list even in case of conflict', function() { + var selectHandler = sinon.stub(); + view.on('select', selectHandler); + var fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch'); + var createStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'create'); + view.$el.find('input').trigger(new $.Event('select2-selecting', { + object: { + id: -1, + name: 'newname', + isNew: true + } + })); + + expect(createStub.calledOnce).toEqual(true); + expect(createStub.getCall(0).args[0]).toEqual({ + name: 'newname', + userVisible: true, + userAssignable: true + }); + + var newModel = new OC.SystemTags.SystemTagModel({ + id: '123', + name: 'newname', + userVisible: true, + userAssignable: true + }); + + // not called yet + expect(selectHandler.notCalled).toEqual(true); + + select2Stub.withArgs('data').returns([{ + id: '1', + name: 'abc' + }]); + + // simulate conflict response for tag creation + createStub.yieldTo('error', view.collection, {status: 409}); + + // at this point it fetches from the server + expect(fetchStub.calledOnce).toEqual(true); + // simulate fetch result by adding model to the collection + view.collection.add(newModel); + fetchStub.yieldTo('success', view.collection); + + expect(select2Stub.lastCall.args[0]).toEqual('data'); + expect(select2Stub.lastCall.args[1]).toEqual([{ + id: '1', + name: 'abc' + }, + newModel.toJSON() + ]); + + // select event still called + expect(selectHandler.calledOnce).toEqual(true); + expect(selectHandler.getCall(0).args[0]).toEqual(newModel); + + createStub.restore(); + fetchStub.restore(); + }); }); describe('tag actions', function() { var opts;