System tags sidebar selector now respects permissions

For admins: display the namespace behind the tag name.
For users: no namespace, don't display non-assignable tags in the
dropdown, display already assigned non-assignable tags with a different
style
This commit is contained in:
Vincent Petry 2016-01-21 15:23:49 +01:00
parent d4198607ec
commit 0a1350d5ac
8 changed files with 463 additions and 264 deletions

View File

@ -28,6 +28,7 @@ $eventDispatcher->addListener(
\OC_Util::addVendorStyle('select2/select2'); \OC_Util::addVendorStyle('select2/select2');
\OCP\Util::addScript('select2-toggleselect'); \OCP\Util::addScript('select2-toggleselect');
\OCP\Util::addScript('oc-backbone-webdav'); \OCP\Util::addScript('oc-backbone-webdav');
\OCP\Util::addScript('systemtags/systemtags');
\OCP\Util::addScript('systemtags/systemtagmodel'); \OCP\Util::addScript('systemtags/systemtagmodel');
\OCP\Util::addScript('systemtags/systemtagsmappingcollection'); \OCP\Util::addScript('systemtags/systemtagsmappingcollection');
\OCP\Util::addScript('systemtags/systemtagscollection'); \OCP\Util::addScript('systemtags/systemtagscollection');

View File

@ -9,6 +9,15 @@
*/ */
(function(OCA) { (function(OCA) {
function modelToSelection(model) {
var data = model.toJSON();
if (!OC.isUserAdmin() && !data.userAssignable) {
data.locked = true;
}
return data;
}
/** /**
* @class OCA.SystemTags.SystemTagsInfoView * @class OCA.SystemTags.SystemTagsInfoView
* @classdesc * @classdesc
@ -36,8 +45,9 @@
multiple: true, multiple: true,
allowActions: true, allowActions: true,
allowCreate: true, allowCreate: true,
isAdmin: OC.isUserAdmin(),
initSelection: function(element, callback) { initSelection: function(element, callback) {
callback(self.selectedTagsCollection.toJSON()); callback(self.selectedTagsCollection.map(modelToSelection));
} }
}); });
@ -108,7 +118,7 @@
this.selectedTagsCollection.fetch({ this.selectedTagsCollection.fetch({
success: function(collection) { success: function(collection) {
collection.fetched = true; collection.fetched = true;
self._inputView.setData(collection.toJSON()); self._inputView.setData(collection.map(modelToSelection));
self.$el.removeClass('hidden'); self.$el.removeClass('hidden');
} }
}); });

View File

@ -20,13 +20,16 @@
*/ */
describe('OCA.SystemTags.SystemTagsInfoView tests', function() { describe('OCA.SystemTags.SystemTagsInfoView tests', function() {
var isAdminStub;
var view; var view;
beforeEach(function() { beforeEach(function() {
view = new OCA.SystemTags.SystemTagsInfoView(); view = new OCA.SystemTags.SystemTagsInfoView();
$('#testArea').append(view.$el); $('#testArea').append(view.$el);
isAdminStub = sinon.stub(OC, 'isUserAdmin').returns(true);
}); });
afterEach(function() { afterEach(function() {
isAdminStub.restore();
view.remove(); view.remove();
view = undefined; view = undefined;
}); });
@ -73,7 +76,7 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() {
view = new OCA.SystemTags.SystemTagsInfoView(); view = new OCA.SystemTags.SystemTagsInfoView();
view.selectedTagsCollection.add([ view.selectedTagsCollection.add([
{id: '1', name: 'test1'}, {id: '1', name: 'test1'},
{id: '3', name: 'test3'} {id: '3', name: 'test3', userVisible: false, userAssignable: false}
]); ]);
var callback = sinon.stub(); var callback = sinon.stub();
@ -83,7 +86,31 @@ describe('OCA.SystemTags.SystemTagsInfoView tests', function() {
expect(callback.getCall(0).args[0]).toEqual([{ expect(callback.getCall(0).args[0]).toEqual([{
id: '1', name: 'test1', userVisible: true, userAssignable: true id: '1', name: 'test1', userVisible: true, userAssignable: true
}, { }, {
id: '3', name: 'test3', userVisible: true, userAssignable: true id: '3', name: 'test3', userVisible: false, userAssignable: false
}]);
inputViewSpy.restore();
});
it('sets locked flag on non-assignable tags when user is not an admin', function() {
isAdminStub.returns(false);
var inputViewSpy = sinon.spy(OC.SystemTags, 'SystemTagsInputField');
var element = $('<input type="hidden" val="1,3"/>');
view.remove();
view = new OCA.SystemTags.SystemTagsInfoView();
view.selectedTagsCollection.add([
{id: '1', name: 'test1'},
{id: '3', name: 'test3', userAssignable: false}
]);
var callback = sinon.stub();
inputViewSpy.getCall(0).args[0].initSelection(element, callback);
expect(callback.calledOnce).toEqual(true);
expect(callback.getCall(0).args[0]).toEqual([{
id: '1', name: 'test1', userVisible: true, userAssignable: true
}, {
id: '3', name: 'test3', userVisible: true, userAssignable: false, locked: true
}]); }]);
inputViewSpy.restore(); inputViewSpy.restore();

View File

@ -69,6 +69,11 @@
margin: 0; margin: 0;
line-height: 20px; line-height: 20px;
} }
.systemtags-select2-container .select2-choices .select2-search-choice.select2-locked .label {
font-style: italic;
}
.systemtags-select2-container .select2-choices .select2-search-choice-close { .systemtags-select2-container .select2-choices .select2-search-choice-close {
display: none; display: none;
} }

View File

@ -37,8 +37,8 @@
return { return {
id: data.id, id: data.id,
name: data.name, name: data.name,
userVisible: data.userVisible === '1', userVisible: data.userVisible === true || data.userVisible === '1',
userAssignable: data.userAssignable === '1' userAssignable: data.userAssignable === true || data.userAssignable === '1'
}; };
} }
}); });

View File

@ -17,7 +17,11 @@
var RESULT_TEMPLATE = var RESULT_TEMPLATE =
'<span class="systemtags-item{{#if isNew}} new-item{{/if}}" data-id="{{id}}">' + '<span class="systemtags-item{{#if isNew}} new-item{{/if}}" data-id="{{id}}">' +
' <span class="checkmark icon icon-checkmark"></span>' + ' <span class="checkmark icon icon-checkmark"></span>' +
'{{#if isAdmin}}' +
' <span class="label">{{{tagMarkup}}}</span>' +
'{{else}}' +
' <span class="label">{{name}}</span>' + ' <span class="label">{{name}}</span>' +
'{{/if}}' +
'{{#allowActions}}' + '{{#allowActions}}' +
' <span class="systemtags-actions">' + ' <span class="systemtags-actions">' +
' <a href="#" class="rename icon icon-rename" title="{{renameTooltip}}"></a>' + ' <a href="#" class="rename icon icon-rename" title="{{renameTooltip}}"></a>' +
@ -25,6 +29,14 @@
'{{/allowActions}}' + '{{/allowActions}}' +
'</span>'; '</span>';
var SELECTION_TEMPLATE =
'{{#if isAdmin}}' +
' <span class="label">{{{tagMarkup}}}</span>' +
'{{else}}' +
' <span class="label">{{name}}</span>' +
'{{/if}}' +
'<span class="comma">,&nbsp;</span>';
var RENAME_FORM_TEMPLATE = var RENAME_FORM_TEMPLATE =
'<form class="systemtags-rename-form">' + '<form class="systemtags-rename-form">' +
' <label class="hidden-visually" for="{{cid}}-rename-input">{{renameLabel}}</label>' + ' <label class="hidden-visually" for="{{cid}}-rename-input">{{renameLabel}}</label>' +
@ -63,6 +75,7 @@
* @param {bool} [options.multiple=false] whether to allow selecting multiple tags * @param {bool} [options.multiple=false] whether to allow selecting multiple tags
* @param {bool} [options.allowActions=true] whether tags can be renamed/delete within the dropdown * @param {bool} [options.allowActions=true] whether tags can be renamed/delete within the dropdown
* @param {bool} [options.allowCreate=true] whether new tags can be created * @param {bool} [options.allowCreate=true] whether new tags can be created
* @param {bool} [options.isAdmin=true] whether the user is an administrator
* @param {Function} options.initSelection function to convert selection to data * @param {Function} options.initSelection function to convert selection to data
*/ */
initialize: function(options) { initialize: function(options) {
@ -71,6 +84,7 @@
this._multiple = !!options.multiple; this._multiple = !!options.multiple;
this._allowActions = _.isUndefined(options.allowActions) || !!options.allowActions; this._allowActions = _.isUndefined(options.allowActions) || !!options.allowActions;
this._allowCreate = _.isUndefined(options.allowCreate) || !!options.allowCreate; this._allowCreate = _.isUndefined(options.allowCreate) || !!options.allowCreate;
this._isAdmin = !!options.isAdmin;
if (_.isFunction(options.initSelection)) { if (_.isFunction(options.initSelection)) {
this._initSelection = options.initSelection; this._initSelection = options.initSelection;
@ -223,9 +237,15 @@
_queryTagsAutocomplete: function(query) { _queryTagsAutocomplete: function(query) {
var self = this; var self = this;
this.collection.fetch({ this.collection.fetch({
success: function() { success: function(collection) {
var tagModels = collection.filterByName(query.term);
if (!self._isAdmin) {
tagModels = _.filter(tagModels, function(tagModel) {
return tagModel.get('userAssignable');
});
}
query.callback({ query.callback({
results: _.invoke(self.collection.filterByName(query.term), 'toJSON') results: _.invoke(tagModels, 'toJSON')
}); });
} }
}); });
@ -247,7 +267,25 @@
} }
return this._resultTemplate(_.extend({ return this._resultTemplate(_.extend({
renameTooltip: t('core', 'Rename'), renameTooltip: t('core', 'Rename'),
allowActions: this._allowActions allowActions: this._allowActions,
tagMarkup: this._isAdmin ? OC.SystemTags.getDescriptiveTag(data)[0].innerHTML : null,
isAdmin: this._isAdmin
}, data));
},
/**
* Formats a single selection item
*
* @param {Object} data data to format
* @return {string} HTML markup
*/
_formatSelection: function(data) {
if (!this._selectionTemplate) {
this._selectionTemplate = Handlebars.compile(SELECTION_TEMPLATE);
}
return this._selectionTemplate(_.extend({
tagMarkup: this._isAdmin ? OC.SystemTags.getDescriptiveTag(data)[0].innerHTML : null,
isAdmin: this._isAdmin
}, data)); }, data));
}, },
@ -266,6 +304,8 @@
this._newTag = { this._newTag = {
id: -1, id: -1,
name: term, name: term,
userAssignable: true,
userVisible: true,
isNew: true isNew: true
}; };
} else { } else {
@ -279,11 +319,20 @@
var self = this; var self = this;
var ids = $(element).val().split(','); var ids = $(element).val().split(',');
function modelToSelection(model) {
var data = model.toJSON();
if (!self._isAdmin && !data.userAssignable) {
// lock static tags for non-admins
data.locked = true;
}
return data;
}
function findSelectedObjects(ids) { function findSelectedObjects(ids) {
var selectedModels = self.collection.filter(function(model) { var selectedModels = self.collection.filter(function(model) {
return ids.indexOf(model.id) >= 0; return ids.indexOf(model.id) >= 0 && (self._isAdmin || model.get('userVisible'));
}); });
return _.invoke(selectedModels, 'toJSON'); return _.map(selectedModels, modelToSelection);
} }
this.collection.fetch({ this.collection.fetch({
@ -316,10 +365,7 @@
}, },
initSelection: _.bind(this._initSelection, this), initSelection: _.bind(this._initSelection, this),
formatResult: _.bind(this._formatDropDownResult, this), formatResult: _.bind(this._formatDropDownResult, this),
formatSelection: function(tag) { formatSelection: _.bind(this._formatSelection, this),
return '<span class="label">' + escapeHTML(tag.name) + '</span>' +
'<span class="comma">,&nbsp;</span>';
},
createSearchChoice: this._allowCreate ? _.bind(this._createSearchChoice, this) : undefined, createSearchChoice: this._allowCreate ? _.bind(this._createSearchChoice, this) : undefined,
sortResults: function(results) { sortResults: function(results) {
var selectedItems = _.pluck(self.$tagsField.select2('data'), 'id'); var selectedItems = _.pluck(self.$tagsField.select2('data'), 'id');

View File

@ -86,6 +86,7 @@ window.firstDay = 0;
// setup dummy webroots // setup dummy webroots
/* jshint camelcase: false */ /* jshint camelcase: false */
window.oc_debug = true; window.oc_debug = true;
window.oc_isadmin = false;
// FIXME: oc_webroot is supposed to be only the path!!! // FIXME: oc_webroot is supposed to be only the path!!!
window.oc_webroot = location.href + '/'; window.oc_webroot = location.href + '/';
window.oc_appswebroots = { window.oc_appswebroots = {

View File

@ -27,8 +27,6 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
select2Stub = sinon.stub($.fn, 'select2'); select2Stub = sinon.stub($.fn, 'select2');
select2Stub.returnsThis(); select2Stub.returnsThis();
$('#testArea').append($container); $('#testArea').append($container);
view = new OC.SystemTags.SystemTagsInputField();
$container.append(view.$el);
}); });
afterEach(function() { afterEach(function() {
select2Stub.restore(); select2Stub.restore();
@ -36,10 +34,20 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
view.remove(); view.remove();
view = undefined; view = undefined;
}); });
describe('rendering', function() {
describe('general behavior', function() {
var $dropdown;
beforeEach(function() { beforeEach(function() {
view = new OC.SystemTags.SystemTagsInputField();
$('.testInputContainer').append(view.$el);
$dropdown = $('<div class="select2-dropdown"></div>');
select2Stub.withArgs('dropdown').returns($dropdown);
$('#testArea').append($dropdown);
view.render(); view.render();
}); });
describe('rendering', function() {
it('calls select2 on rendering', function() { it('calls select2 on rendering', function() {
expect(view.$el.find('input[name=tags]').length).toEqual(1); expect(view.$el.find('input[name=tags]').length).toEqual(1);
expect(select2Stub.called).toEqual(true); expect(select2Stub.called).toEqual(true);
@ -47,60 +55,20 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
it('formatResult renders rename button', function() { it('formatResult renders rename button', function() {
var opts = select2Stub.getCall(0).args[0]; var opts = select2Stub.getCall(0).args[0];
var $el = $(opts.formatResult({id: '1', name: 'test'})); var $el = $(opts.formatResult({id: '1', name: 'test'}));
expect($el.find('.label').text()).toEqual('test');
expect($el.find('.rename').length).toEqual(1); expect($el.find('.rename').length).toEqual(1);
}); });
}); });
describe('initSelection', function() {
var fetchStub;
var testTags;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
testTags = [
new OC.SystemTags.SystemTagModel({id: '1', name: 'test1'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'test2'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'test3'}),
];
view.render();
});
afterEach(function() {
fetchStub.restore();
});
it('grabs values from the full collection', function() {
var $el = view.$el.find('input');
$el.val('1,3');
var opts = select2Stub.getCall(0).args[0];
var callback = sinon.stub();
opts.initSelection($el, callback);
expect(fetchStub.calledOnce).toEqual(true);
view.collection.add(testTags);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
var models = callback.getCall(0).args[0];
expect(models.length).toEqual(2);
expect(models[0].id).toEqual('1');
expect(models[0].name).toEqual('test1');
expect(models[1].id).toEqual('3');
expect(models[1].name).toEqual('test3');
});
});
describe('tag selection', function() { describe('tag selection', function() {
beforeEach(function() { beforeEach(function() {
view.render();
var $el = view.$el.find('input'); var $el = view.$el.find('input');
$el.val('1'); $el.val('1');
view.collection.add([ view.collection.add([
new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}), new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}), new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'abd'}), new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
]); ]);
}); });
afterEach(function() {
});
it('does not create dummy tag when user types non-matching name', function() { it('does not create dummy tag when user types non-matching name', function() {
var opts = select2Stub.getCall(0).args[0]; var opts = select2Stub.getCall(0).args[0];
var result = opts.createSearchChoice('abc'); var result = opts.createSearchChoice('abc');
@ -112,6 +80,8 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
expect(result.id).toEqual(-1); expect(result.id).toEqual(-1);
expect(result.name).toEqual('abnew'); expect(result.name).toEqual('abnew');
expect(result.isNew).toEqual(true); expect(result.isNew).toEqual(true);
expect(result.userVisible).toEqual(true);
expect(result.userAssignable).toEqual(true);
}); });
it('creates the real tag and fires select event after user selects the dummy tag', function() { it('creates the real tag and fires select event after user selects the dummy tag', function() {
var selectHandler = sinon.stub(); var selectHandler = sinon.stub();
@ -189,59 +159,10 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
expect(selectHandler.getCall(0).args[0]).toEqual('2'); expect(selectHandler.getCall(0).args[0]).toEqual('2');
}); });
}); });
describe('autocomplete', function() {
var fetchStub, opts;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
view.render();
opts = select2Stub.getCall(0).args[0];
view.collection.add([
new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'abd'}),
]);
});
afterEach(function() {
fetchStub.restore();
});
it('completes results', function() {
var callback = sinon.stub();
opts.query({
term: 'ab',
callback: callback
});
expect(fetchStub.calledOnce).toEqual(true);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
expect(callback.getCall(0).args[0].results).toEqual([
{
id: '1',
name: 'abc',
userVisible: true,
userAssignable: true
},
{
id: '3',
name: 'abd',
userVisible: true,
userAssignable: true
}
]);
});
});
describe('tag actions', function() { describe('tag actions', function() {
var $dropdown, opts; var opts;
beforeEach(function() { beforeEach(function() {
$dropdown = $('<div class="select2-dropdown"></div>');
select2Stub.withArgs('dropdown').returns($dropdown);
$('#testArea').append($dropdown);
view.render();
opts = select2Stub.getCall(0).args[0]; opts = select2Stub.getCall(0).args[0];
@ -251,8 +172,6 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
$dropdown.append(opts.formatResult(view.collection.get('1').toJSON())); $dropdown.append(opts.formatResult(view.collection.get('1').toJSON()));
});
afterEach(function() {
}); });
it('displays rename form when clicking rename', function() { it('displays rename form when clicking rename', function() {
$dropdown.find('.rename').mouseup(); $dropdown.find('.rename').mouseup();
@ -289,9 +208,6 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
}); });
}); });
describe('setting data', function() { describe('setting data', function() {
beforeEach(function() {
view.render();
});
it('sets value when calling setValues', function() { it('sets value when calling setValues', function() {
var vals = ['1', '2']; var vals = ['1', '2'];
view.setValues(vals); view.setValues(vals);
@ -306,3 +222,196 @@ describe('OC.SystemTags.SystemTagsInputField tests', function() {
}); });
}); });
}); });
describe('as admin', function() {
beforeEach(function() {
view = new OC.SystemTags.SystemTagsInputField({
isAdmin: true
});
view.render();
$('.testInputContainer').append(view.$el);
});
it('formatResult renders tag name with visibility', function() {
var opts = select2Stub.getCall(0).args[0];
var $el = $(opts.formatResult({id: '1', name: 'test', userVisible: false, userAssignable: false}));
expect($el.find('.label').text()).toEqual('test (invisible, not assignable)');
});
it('formatSelection renders tag name with visibility', function() {
var opts = select2Stub.getCall(0).args[0];
var $el = $(opts.formatSelection({id: '1', name: 'test', userVisible: false, userAssignable: false}));
expect($el.text().trim()).toEqual('test (invisible, not assignable),');
});
describe('initSelection', function() {
var fetchStub;
var testTags;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
testTags = [
new OC.SystemTags.SystemTagModel({id: '1', name: 'test1'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'test2'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'test3', userAssignable: false}),
];
});
afterEach(function() {
fetchStub.restore();
});
it('grabs values from the full collection', function() {
var $el = view.$el.find('input');
$el.val('1,3');
var opts = select2Stub.getCall(0).args[0];
var callback = sinon.stub();
opts.initSelection($el, callback);
expect(fetchStub.calledOnce).toEqual(true);
view.collection.add(testTags);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
var models = callback.getCall(0).args[0];
expect(models.length).toEqual(2);
expect(models[0].id).toEqual('1');
expect(models[0].name).toEqual('test1');
expect(models[1].id).toEqual('3');
expect(models[1].name).toEqual('test3');
});
});
describe('autocomplete', function() {
var fetchStub, opts;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
opts = select2Stub.getCall(0).args[0];
view.collection.add([
new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
]);
});
afterEach(function() {
fetchStub.restore();
});
it('completes results', function() {
var callback = sinon.stub();
opts.query({
term: 'ab',
callback: callback
});
expect(fetchStub.calledOnce).toEqual(true);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
expect(callback.getCall(0).args[0].results).toEqual([
{
id: '1',
name: 'abc',
userVisible: true,
userAssignable: true
},
{
id: '3',
name: 'abd',
userVisible: true,
userAssignable: false
}
]);
});
});
});
describe('as user', function() {
beforeEach(function() {
view = new OC.SystemTags.SystemTagsInputField({
isAdmin: false
});
view.render();
$('.testInputContainer').append(view.$el);
});
it('formatResult renders tag name only', function() {
var opts = select2Stub.getCall(0).args[0];
var $el = $(opts.formatResult({id: '1', name: 'test'}));
expect($el.find('.label').text()).toEqual('test');
});
it('formatSelection renders tag name only', function() {
var opts = select2Stub.getCall(0).args[0];
var $el = $(opts.formatSelection({id: '1', name: 'test'}));
expect($el.text().trim()).toEqual('test,');
});
describe('initSelection', function() {
var fetchStub;
var testTags;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
testTags = [
new OC.SystemTags.SystemTagModel({id: '1', name: 'test1'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'test2'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'test3', userAssignable: false}),
];
view.render();
});
afterEach(function() {
fetchStub.restore();
});
it('grabs values from the full collection', function() {
var $el = view.$el.find('input');
$el.val('1,3');
var opts = select2Stub.getCall(0).args[0];
var callback = sinon.stub();
opts.initSelection($el, callback);
expect(fetchStub.calledOnce).toEqual(true);
view.collection.add(testTags);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
var models = callback.getCall(0).args[0];
expect(models.length).toEqual(2);
expect(models[0].id).toEqual('1');
expect(models[0].name).toEqual('test1');
expect(models[1].id).toEqual('3');
expect(models[1].name).toEqual('test3');
});
});
describe('autocomplete', function() {
var fetchStub, opts;
beforeEach(function() {
fetchStub = sinon.stub(OC.SystemTags.SystemTagsCollection.prototype, 'fetch');
view.render();
opts = select2Stub.getCall(0).args[0];
view.collection.add([
new OC.SystemTags.SystemTagModel({id: '1', name: 'abc'}),
new OC.SystemTags.SystemTagModel({id: '2', name: 'def'}),
new OC.SystemTags.SystemTagModel({id: '3', name: 'abd', userAssignable: false}),
]);
});
afterEach(function() {
fetchStub.restore();
});
it('completes results excluding non-assignable tags', function() {
var callback = sinon.stub();
opts.query({
term: 'ab',
callback: callback
});
expect(fetchStub.calledOnce).toEqual(true);
fetchStub.yieldTo('success', view.collection);
expect(callback.calledOnce).toEqual(true);
expect(callback.getCall(0).args[0].results).toEqual([
{
id: '1',
name: 'abc',
userVisible: true,
userAssignable: true
}
]);
});
});
});
});