/*jslint vars: true, unparam: true */
/*global jQuery, IQVOC */
IQVOC.EntitySelector = (function($) {
"use strict";
var EntitySelector = function(node) {
if(!(this instanceof EntitySelector)) { // "new" keyword optional
return new EntitySelector(node);
}
this.el = $(node).hide(); // XXX: rename
this.container = $('
').data("widget", this);
this.delimiter = ",";
this.singular = this.el.data("singular") || false;
this.entities = this.getSelection();
this.uriTemplate = this.el.data("entity-uri");
var self = this;
var selection = $.map(this.el.data("entities"), function(entity, i) {
return self.createEntity(entity);
});
selection = $('').append(selection);
var exclude = this.el.data("exclude") || null;
var img = $('');
this.input = $("").autocomplete({
minLength: 3,
source: function(req, callback) {
var uri = self.el.data("query-url");
$.getJSON(uri, { query: req.term }, function(data, status, xhr) { // TODO: error handling
var excludes = self.getSelection()
.concat(exclude ? [exclude] : []);
data = $.map(data, function(entity, i) {
return $.inArray(entity.id, excludes) !== -1 ? null :
{ value: entity.id, label: entity.name };
});
self.input.autocomplete("option", "autoFocus", data.length === 1);
callback(data);
img.addClass("hidden");
});
},
search: function(ev, ui) { img.removeClass("hidden"); },
focus: function(ev, ui) { return false; },
select: this.onSelect
});
this.container.append(this.input).append(img).append(selection)
.insertAfter(node).prepend(node);
if(this.singular && this.entities.length) {
this.input.hide();
}
};
$.extend(EntitySelector.prototype, {
onSelect: function(ev, ui) {
var el = $(this).val("");
var widget = el.closest(".entity_select").data("widget");
if(widget.add(ui.item.value)) {
var entity = widget
.createEntity({ id: ui.item.value, name: ui.item.label });
widget.container.find("ul").append(entity);
if(widget.singular) {
widget.input.hide();
}
}
return false;
},
onDelete: function(ev) {
var el = $(this);
var entity = el.closest("li");
var widget = el.closest(".entity_select").data("widget");
widget.remove(entity.data("id"));
entity.remove();
if(widget.singular && !widget.entities.length) {
widget.input.show();
}
ev.preventDefault();
},
createEntity: function(entity) {
var el;
if(this.uriTemplate) {
var uri = this.uriTemplate.replace("%7Bid%7D", entity.id); // XXX: not very generic
el = $('').attr("href", uri).text(entity.name);
} else {
el = $('').text(entity.name);
}
var btn = $('x') // "btn" to avoid fancy "button" class -- XXX: hacky workaround!?
.click(this.onDelete);
return $("").data("id", entity.id).append(el).append(btn)[0];
},
add: function(entity) {
if($.inArray(entity, this.entities) === -1) {
this.entities.push(entity);
this.setSelection();
return true;
} else {
return false;
}
},
remove: function(entity) {
var pos = $.inArray(entity, this.entities);
if(pos !== -1) {
this.entities.splice(pos, 1);
this.setSelection();
}
},
setSelection: function() {
this.el.val(this.entities.join(this.delimiter));
},
getSelection: function() {
return $.map(this.el.val().split(this.delimiter), function(entity, i) {
return entity ? $.trim(entity) : null;
});
}
});
return EntitySelector;
}(jQuery));