2018-05-25 17:53:25 +02:00
|
|
|
/*!
|
|
|
|
* Tag Selector plugin for jQuery: Facilitates selecting multiple tags by extending jQuery UI Autocomplete.
|
|
|
|
* You may use Tag Selector under the terms of either the MIT License or the GNU General Public License (GPL) Version 2.
|
|
|
|
* https://petprojects.googlecode.com/svn/trunk/MIT-LICENSE.txt
|
|
|
|
* https://petprojects.googlecode.com/svn/trunk/GPL-LICENSE.txt
|
|
|
|
*/
|
|
|
|
(function($) {
|
2018-12-22 12:23:58 +01:00
|
|
|
function hide_error(input) {
|
|
|
|
var err = input.parent().parent().find(".invalid-remaining");
|
|
|
|
err.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
function show_error(input, msg) {
|
|
|
|
var err = input.parent().parent().find(".invalid-remaining");
|
|
|
|
console.log(err.length);
|
|
|
|
err.text(msg);
|
|
|
|
err.show();
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:15:35 +02:00
|
|
|
$.fn.selectSelector = function(source, name, select) {
|
2018-05-25 17:53:25 +02:00
|
|
|
return this.each(function() {
|
|
|
|
var selector = $(this),
|
|
|
|
input = $('input[type=text]', this);
|
|
|
|
|
|
|
|
selector.click(function() { input.focus(); })
|
2018-12-22 12:23:58 +01:00
|
|
|
.delegate('.badge a', 'click', function() {
|
2018-05-25 17:53:25 +02:00
|
|
|
var id = $(this).parent().data("id");
|
|
|
|
for (var i = 0; i < source.length; i++) {
|
|
|
|
if (source[i].id == id) {
|
|
|
|
source[i].selected = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
select.find("option[value=" + id + "]").attr("selected", null)
|
|
|
|
recreate();
|
|
|
|
});
|
|
|
|
|
|
|
|
function addTag(item) {
|
2018-12-22 12:23:58 +01:00
|
|
|
var tag = $('<span class="badge badge-pill badge-primary"/>')
|
2018-05-25 17:53:25 +02:00
|
|
|
.text(item.toString() + ' ')
|
|
|
|
.data("id", item.id)
|
|
|
|
.append('<a>x</a>')
|
|
|
|
.insertBefore(input);
|
|
|
|
input.attr("placeholder", null);
|
|
|
|
select.find("option[value=" + item.id + "]").attr("selected", "selected")
|
2018-12-22 12:23:58 +01:00
|
|
|
hide_error(input);
|
2018-05-25 17:53:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function recreate() {
|
|
|
|
selector.find("span").remove();
|
|
|
|
for (var i = 0; i < source.length; i++) {
|
|
|
|
if (source[i].selected) {
|
|
|
|
addTag(source[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
recreate();
|
|
|
|
|
2018-12-22 12:23:58 +01:00
|
|
|
input.focusout(function(e) {
|
|
|
|
var value = input.val().trim()
|
|
|
|
if (value != "") {
|
|
|
|
show_error(input, "Please select an existing tag, it;s not possible to add custom ones.");
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2018-05-25 17:53:25 +02:00
|
|
|
input.keydown(function(e) {
|
|
|
|
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('ui-autocomplete').menu.active)
|
|
|
|
e.preventDefault();
|
|
|
|
})
|
|
|
|
.autocomplete({
|
|
|
|
minLength: 0,
|
|
|
|
source: source,
|
|
|
|
select: function(event, ui) {
|
|
|
|
addTag(ui.item);
|
|
|
|
input.val("");
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-26 01:28:52 +02:00
|
|
|
}).focus(function() {
|
|
|
|
// The following works only once.
|
|
|
|
// $(this).trigger('keydown.autocomplete');
|
|
|
|
// As suggested by digitalPBK, works multiple times
|
|
|
|
// $(this).data("autocomplete").search($(this).val());
|
|
|
|
// As noted by Jonny in his answer, with newer versions use uiAutocomplete
|
|
|
|
$(this).data("ui-autocomplete").search($(this).val());
|
2018-05-25 17:53:25 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
input.data('ui-autocomplete')._renderItem = function(ul, item) {
|
|
|
|
return $('<li/>')
|
|
|
|
.data('item.autocomplete', item)
|
|
|
|
.append($('<a/>').text(item.toString()))
|
|
|
|
.appendTo(ul);
|
|
|
|
};
|
|
|
|
|
|
|
|
input.data('ui-autocomplete')._resizeMenu = function(ul, item) {
|
|
|
|
var ul = this.menu.element;
|
|
|
|
ul.outerWidth(Math.max(
|
|
|
|
ul.width('').outerWidth(),
|
|
|
|
selector.outerWidth()
|
|
|
|
));
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:15:35 +02:00
|
|
|
$.fn.csvSelector = function(source, name, result, allowSlash) {
|
|
|
|
return this.each(function() {
|
|
|
|
var selector = $(this),
|
|
|
|
input = $('input[type=text]', this);
|
|
|
|
|
|
|
|
var selected = [];
|
2018-05-27 22:31:11 +02:00
|
|
|
var lookup = {};
|
|
|
|
for (var i = 0; i < source.length; i++) {
|
|
|
|
lookup[source[i].id] = source[i];
|
|
|
|
}
|
|
|
|
|
2018-05-27 21:15:35 +02:00
|
|
|
selector.click(function() { input.focus(); })
|
2018-12-22 12:23:58 +01:00
|
|
|
.delegate('.badge a', 'click', function() {
|
2018-05-27 21:15:35 +02:00
|
|
|
var id = $(this).parent().data("id");
|
|
|
|
for (var i = 0; i < selected.length; i++) {
|
|
|
|
if (selected[i] == id) {
|
|
|
|
selected.splice(i, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
recreate();
|
|
|
|
});
|
|
|
|
|
|
|
|
function selectItem(id) {
|
|
|
|
for (var i = 0; i < selected.length; i++) {
|
|
|
|
if (selected[i] == id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
selected.push(id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addTag(id, value) {
|
2018-12-22 12:23:58 +01:00
|
|
|
var tag = $('<span class="badge badge-pill badge-primary"/>')
|
2018-05-27 21:15:35 +02:00
|
|
|
.text(value)
|
|
|
|
.data("id", id)
|
|
|
|
.append(' <a>x</a>')
|
|
|
|
.insertBefore(input);
|
|
|
|
|
|
|
|
input.attr("placeholder", null);
|
2018-12-22 12:23:58 +01:00
|
|
|
hide_error(input);
|
2018-05-27 21:15:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function recreate() {
|
|
|
|
selector.find("span").remove();
|
|
|
|
for (var i = 0; i < selected.length; i++) {
|
2018-05-27 22:31:11 +02:00
|
|
|
var value = lookup[selected[i]] || { value: selected[i] };
|
|
|
|
addTag(selected[i], value.value);
|
2018-05-27 21:15:35 +02:00
|
|
|
}
|
|
|
|
result.val(selected.join(","))
|
|
|
|
}
|
2018-05-27 23:03:54 +02:00
|
|
|
|
|
|
|
function readFromResult() {
|
|
|
|
selected = [];
|
|
|
|
var selected_raw = result.val().split(",");
|
|
|
|
for (var i = 0; i < selected_raw.length; i++) {
|
|
|
|
var raw = selected_raw[i].trim();
|
|
|
|
if (lookup[raw] || raw.match(/^([a-z0-9_]+)$/)) {
|
|
|
|
selected.push(raw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
recreate();
|
|
|
|
}
|
|
|
|
readFromResult();
|
|
|
|
|
|
|
|
result.change(readFromResult);
|
2018-05-27 21:15:35 +02:00
|
|
|
|
2018-12-22 12:23:58 +01:00
|
|
|
input.focusout(function() {
|
|
|
|
var item = input.val();
|
|
|
|
if (item.length == 0) {
|
|
|
|
input.data("ui-autocomplete").search("");
|
|
|
|
} else if (item.match(/^([a-z0-9_]+)$/)) {
|
|
|
|
selectItem(item);
|
|
|
|
recreate();
|
|
|
|
input.val("");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2018-05-27 21:15:35 +02:00
|
|
|
input.keydown(function(e) {
|
|
|
|
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('ui-autocomplete').menu.active)
|
|
|
|
e.preventDefault();
|
|
|
|
else if (e.keyCode === $.ui.keyCode.COMMA) {
|
|
|
|
var item = input.val();
|
2018-05-27 22:31:11 +02:00
|
|
|
if (item.length == 0) {
|
|
|
|
input.data("ui-autocomplete").search("");
|
|
|
|
} else if (item.match(/^([a-z0-9_]+)$/)) {
|
2018-05-27 21:15:35 +02:00
|
|
|
selectItem(item);
|
|
|
|
recreate();
|
|
|
|
input.val("");
|
|
|
|
} else {
|
2018-12-22 12:23:58 +01:00
|
|
|
show_error(input, "Only lowercase alphanumeric and number names allowed.");
|
2018-05-27 21:15:35 +02:00
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
return true;
|
|
|
|
} else if (e.keyCode === $.ui.keyCode.BACKSPACE) {
|
|
|
|
if (input.val() == "") {
|
|
|
|
var item = selected[selected.length - 1];
|
|
|
|
selected.splice(selected.length - 1, 1);
|
|
|
|
recreate();
|
2018-05-27 22:31:11 +02:00
|
|
|
if (!(item.indexOf("/") > 0))
|
|
|
|
input.val(item);
|
2018-05-27 21:15:35 +02:00
|
|
|
e.preventDefault();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.autocomplete({
|
|
|
|
minLength: 0,
|
|
|
|
source: source,
|
|
|
|
select: function(event, ui) {
|
|
|
|
selectItem(ui.item.id);
|
|
|
|
recreate();
|
|
|
|
input.val("");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
input.data('ui-autocomplete')._renderItem = function(ul, item) {
|
|
|
|
return $('<li/>')
|
|
|
|
.data('item.autocomplete', item)
|
|
|
|
.append($('<a/>').text(item.toString()))
|
|
|
|
.appendTo(ul);
|
|
|
|
};
|
|
|
|
|
|
|
|
input.data('ui-autocomplete')._resizeMenu = function(ul, item) {
|
|
|
|
var ul = this.menu.element;
|
|
|
|
ul.outerWidth(Math.max(
|
|
|
|
ul.width('').outerWidth(),
|
|
|
|
selector.outerWidth()
|
|
|
|
));
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-25 17:53:25 +02:00
|
|
|
$(function() {
|
|
|
|
$(".multichoice_selector").each(function() {
|
|
|
|
var ele = $(this);
|
|
|
|
var sel = ele.parent().find("select");
|
2018-05-27 21:15:35 +02:00
|
|
|
sel.hide();
|
2018-05-25 17:53:25 +02:00
|
|
|
|
|
|
|
var options = [];
|
|
|
|
sel.find("option").each(function() {
|
|
|
|
var text = $(this).text();
|
|
|
|
options.push({
|
|
|
|
id: $(this).attr("value"),
|
|
|
|
value: text,
|
|
|
|
selected: $(this).attr("selected") ? true : false,
|
|
|
|
toString: function() { return text; },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log(options);
|
2018-05-27 21:15:35 +02:00
|
|
|
ele.selectSelector(options, sel.attr("name"), sel);
|
|
|
|
});
|
|
|
|
|
|
|
|
$(".metapackage_selector").each(function() {
|
|
|
|
var input = $(this).parent().children("input[type='text']");
|
|
|
|
input.hide();
|
|
|
|
$(this).csvSelector(meta_packages, input.attr("name"), input);
|
2018-05-27 22:31:11 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
$(".deps_selector").each(function() {
|
|
|
|
var input = $(this).parent().children("input[type='text']");
|
|
|
|
input.hide();
|
|
|
|
$(this).csvSelector(all_packages, input.attr("name"), input);
|
|
|
|
});
|
2018-05-25 17:53:25 +02:00
|
|
|
});
|
|
|
|
})(jQuery);
|