diff --git a/pom.xml b/pom.xml
index 7861c54194facc58253a45bbdeb404646b500ac9..b3f53c7a36f38200812d98b3cfc844a1be28022f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -247,7 +247,7 @@
 											<output>${basedir}/src/main/webapp/static/js/js.plugins.min.css</output>
 											<removeIncluded>false</removeIncluded>
 											<includes>
-												<include>${basedir}/target/jquery/jquery/tagit/jquery.tagit.min.css</include>
+												<include>${basedir}/target/jquery/jquery/tagsinput/bootstrap-tagsinput.min.css</include>
 												<include>${basedir}/target/jquery/jquery/uilayout/layout-default-latest.min.css</include>
 												<include>${basedir}/target/jquery/jquery/fullcalendar/fullcalendar.min.css</include>
 												<include>${basedir}/src/main/webapp/static/js/jquery/datatables/css/jquery.dataTables.css</include>
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html b/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html
index 847442833a9910180ca0046382e85fbf11f038fc..4426e1c3ba692458bc3ace79ca24501d1d14962e 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html
+++ b/src/main/java/org/olat/core/commons/fullWebApp/_content/fullwebapplayout.html
@@ -104,8 +104,8 @@ function b_start(){
 <script type="text/javascript" src='$r.staticLink("movie/player.js")'></script>
 
 ## Always loaded
-## <link type="text/css" href='$r.staticLink("js/jquery/tagit/jquery.tagit.css")' rel="stylesheet"/>
 ## <link type="text/css" href='$r.staticLink("js/jquery/uilayout/layout-default-latest.css")' rel="stylesheet"/>
+<link type="text/css" href='$r.staticLink("js/jquery/tagsinput/bootstrap-tagsinput.css")' rel="stylesheet"/>
 <link type="text/css" href='$r.staticLink("js/jquery/fullcalendar/fullcalendar.css")' rel="stylesheet"/>
 <link type="text/css" href='$r.staticLink("js/jquery/datatables/css/jquery.dataTables.css")' rel="stylesheet"/>
 ## FIXME:oo10 add plugin min
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java
index ca03e597bc73198b42ed769fdfd7022514397fdb..b65287c065bb11fa6ad05a9d42dc8b374d96e16e 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/TextBoxListElementImpl.java
@@ -45,11 +45,10 @@ import org.olat.core.util.Util;
  */
 public class TextBoxListElementImpl extends AbstractTextElement implements TextBoxListElement {
 
-
 	/**
 	 * the wrapped textBoxListElementComponent
 	 */
-	private TextBoxListElementComponent component;
+	private final TextBoxListElementComponent component;
 
 	public TextBoxListElementImpl(String name, String inputHint, Map<String, String> initialItems, Translator translator) {
 		super(name,true);// we wan't to be an inline-editing element!
diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java
index 214de503c04b2dce5a3dd191e8ad66af34eae835..0d5d16be33252edd450cacb2e307beb47a5bede0 100644
--- a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java
+++ b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListComponent.java
@@ -286,11 +286,11 @@ public abstract class TextBoxListComponent extends FormBaseComponentImpl {
 	public void validate(UserRequest ureq, ValidationResult vr) {
 		super.validate(ureq, vr);
 		JSAndCSSAdder jsa = vr.getJsAndCSSAdder();
-		//jsa.addRequiredJsFile(TextBoxListComponent.class, "js/multiselect.js");
-		jsa.addRequiredStaticJsFile("js/jquery/tagit/tag-it.min.js");
-
-		if (provider != null)
+		jsa.addRequiredStaticJsFile("js/jquery/tagsinput/bootstrap-tagsinput.min.js");
+		if (provider != null) {
+			jsa.addRequiredStaticJsFile("js/jquery/typeahead/typeahead.bundle.min.js");
 			setMapper(ureq);
+		}
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java
index c66c32df486ee58b1c90b34dc2a94f8aad640b09..e2c5ddfbb57e0cb549a3c9525461516e62c33225 100644
--- a/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/textboxlist/TextBoxListRenderer.java
@@ -19,25 +19,17 @@
  */
 package org.olat.core.gui.components.textboxlist;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.DefaultComponentRenderer;
 import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
 import org.olat.core.gui.components.form.flexible.impl.elements.TextBoxListElementComponent;
 import org.olat.core.gui.components.form.flexible.impl.elements.TextBoxListElementImpl;
 import org.olat.core.gui.render.RenderResult;
 import org.olat.core.gui.render.Renderer;
-import org.olat.core.gui.render.RenderingState;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.filter.impl.OWASPAntiSamyXSSFilter;
 
 /**
  * Description:<br>
@@ -49,16 +41,7 @@ import org.olat.core.util.filter.impl.OWASPAntiSamyXSSFilter;
  * 
  * @author Roman Haag, roman.haag@frentix.com, http://www.frentix.com
  */
-public class TextBoxListRenderer implements ComponentRenderer {
-
-	private static OLog logger = Tracing.createLoggerFor(TextBoxListRenderer.class);
-	
-	/**
-	 * default constructor
-	 */
-	public TextBoxListRenderer() {
-
-	}
+public class TextBoxListRenderer extends DefaultComponentRenderer {
 
 	/**
 	 * @see org.olat.core.gui.components.ComponentRenderer#render(org.olat.core.gui.render.Renderer,
@@ -74,11 +57,10 @@ public class TextBoxListRenderer implements ComponentRenderer {
 
 		TextBoxListComponent tblComponent = (TextBoxListElementComponent) source;
 		if (tblComponent.isEnabled()) {
-			renderEnabledMode(tblComponent, sb, translator);
+			renderEnabledMode(tblComponent, sb);
 		} else {
 			renderDisabledMode(tblComponent, sb);
 		}
-
 	}
 
 	/**
@@ -86,97 +68,40 @@ public class TextBoxListRenderer implements ComponentRenderer {
 	 * 
 	 * @param tblComponent
 	 *            the component to render
-	 * @param output
+	 * @param sb
 	 *            the StringOutput
 	 * @param translator
 	 */
-	private void renderEnabledMode(TextBoxListComponent tblComponent, StringOutput output, Translator translator) {
-		
-		/* if in debug mode, create more readable javascript code */
-		String lineBreak = "";
-		if(logger.isDebug()){
-			lineBreak = Character.toString((char)10);
-			logger.debug("rendering TextBoxListComponent in debug mode, nice JS output.");
-		}
-		
+	private void renderEnabledMode(TextBoxListComponent tblComponent, StringOutput sb) {
 		TextBoxListElementImpl te = ((TextBoxListElementComponent)tblComponent).getTextElementImpl();
 		Form rootForm = te.getRootForm();
 		String dispatchId = tblComponent.getFormDispatchId();
 		String initialValue = tblComponent.getInitialItemsAsString();
 
-		output.append("<input type=\"text\" id=\"textboxlistinput").append(dispatchId).append("\" ")
-		      .append("name='textboxlistinput").append(dispatchId).append("' ")
-		      .append("value='").append(initialValue).append("'")
-		      .append("/>\n");
-
-		// OO-137 : here, we display the currentItems. (at first render, this is equal to initialItems)
-		// on succeeding rendering, we want to reflect the current component status
+		sb.append("<input type='text' id='textboxlistinput").append(dispatchId).append("'")
+		  .append(" name='textboxlistinput").append(dispatchId).append("'")
+		  .append(" value='").append(initialValue).append("' />\n");
 
-		// generate the JS-code for the tagit
-		output.append(FormJSHelper.getJSStart());
-		output.append("jQuery(function(){\n")
-		      .append("  jQuery('#textboxlistinput").append(dispatchId).append("').tagit({\n")
-		      .append("    allowDuplicates:").append(tblComponent.isAllowDuplicates()).append(",\n")
-		      .append("    autocomplete: {\n")
-		      .append("      delay: 100,");
+		String o_ffEvent = FormJSHelper.getJSFnCallFor(rootForm, dispatchId, 2);
+		// generate the JS-code for the bootstrap tagsinput
+		sb.append(FormJSHelper.getJSStart())
+		  .append("jQuery(function(){\n")
+		  .append("  jQuery('#textboxlistinput").append(dispatchId).append("').tagsinput({\n");
 		
-		//set autocompleter.source if a provider is around
 		if (tblComponent.getProvider() != null) {
-			String mapperUri = tblComponent.getMapperUri();
-			output.append("    source: function(request, response) {\n")
-			      .append("      jQuery.ajax('").append(mapperUri).append("',{\n")
-			      .append("        data: request,\n")
-			      .append("        dataType:'json',\n")
-			      .append("        success: function(data) {\n")
-			      .append("          response(jQuery.map(data, function( item ) {\n")
-			      .append("            return item;\n")
-			      .append("          }));\n")
-			      .append("        }\n")
-			      .append("      });\n")
-			      .append("    },\n");
+			sb.append("    typeahead: {\n")
+			  .append("      source: function() {")
+			  .append("      	return jQuery.getJSON('").append(tblComponent.getMapperUri()).append("');")
+			  .append("      }")
+			  .append("    }\n");
 		}
- 
-		output.append("      minLength: 2\n")
-		      .append("    },\n")
-		      .append("    availableTags:[");
-
-		OWASPAntiSamyXSSFilter filter = new OWASPAntiSamyXSSFilter();
-		Map<String, String> initItems = tblComponent.getCurrentItems();
-		if (initItems != null) {
-			boolean sep = true;
-			for (Entry<String, String> item :initItems.entrySet()) {
-				if(sep) sep = false;
-				else output.append(",");
-
-				String value;
-				if (StringHelper.containsNonWhitespace(item.getValue())) {
-					value = item.getValue();
-				} else {
-					value = item.getKey();
-				}
-				value = filter.filter(value);
-				value = StringHelper.escapeHtml(value);
-				output.append("'").append(value).append("'");
-			}
-		}
-    output.append("],\n");  
-		
-		// otherwise, o_ffEvents are fired: OO-137 ( invoke o_ffEvent on UserAdd or userRemove ) but only in flexiform
-		String o_ffEvent = FormJSHelper.getJSFnCallFor(rootForm, dispatchId, 2);
-		output.append("    afterTagAdded: function(event,ui){\n")
-		      .append("      if(!ui.duringInitialization) {")
-			    .append(o_ffEvent).append(";\n")
-			    .append("      }\n")
-			    .append("    },\n")
-			    .append("    afterTagRemoved: function(event,ui){\n")
-		      .append("      if(!ui.duringInitialization) {")
-			    .append(o_ffEvent).append(";\n")
-			    .append("      }\n")
-			    .append("    }\n")
-		      .append("  });\n")
-		      .append("})\n");
 		
-		output.append(FormJSHelper.getJSEnd()).append(lineBreak);
+		sb.append("  });\n")
+		  .append("  jQuery('#textboxlistinput").append(dispatchId).append("').on('itemAdded itemRemoved',function(event) {\n")
+		  .append(o_ffEvent).append(";\n")
+		  .append("  });\n")
+		  .append("});\n")
+		  .append(FormJSHelper.getJSEnd());
 	}
 
 	/**
@@ -197,30 +122,4 @@ public class TextBoxListRenderer implements ComponentRenderer {
 			FormJSHelper.appendReadOnly("-", output);
 		}
 	}
-
-	/**
-	 * @see org.olat.core.gui.components.ComponentRenderer#renderHeaderIncludes(org.olat.core.gui.render.Renderer,
-	 *      org.olat.core.gui.render.StringOutput,
-	 *      org.olat.core.gui.components.Component,
-	 *      org.olat.core.gui.render.URLBuilder,
-	 *      org.olat.core.gui.translator.Translator,
-	 *      org.olat.core.gui.render.RenderingState)
-	 */
-	@Override
-	public void renderHeaderIncludes(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
-			RenderingState rstate) {
-		// nothing
-	}
-
-	/**
-	 * @see org.olat.core.gui.components.ComponentRenderer#renderBodyOnLoadJSFunctionCall(org.olat.core.gui.render.Renderer,
-	 *      org.olat.core.gui.render.StringOutput,
-	 *      org.olat.core.gui.components.Component,
-	 *      org.olat.core.gui.render.RenderingState)
-	 */
-	@Override
-	public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source, RenderingState rstate) {
-		// nothing to load
-	}
-
 }
diff --git a/src/main/java/org/olat/core/gui/control/JSAndCSSAdder.java b/src/main/java/org/olat/core/gui/control/JSAndCSSAdder.java
index abe8046d05823c4f25ff544444c0a375e5253ed6..859d3a21d930f43fc0d88ea76b2bdcd32282e802 100644
--- a/src/main/java/org/olat/core/gui/control/JSAndCSSAdder.java
+++ b/src/main/java/org/olat/core/gui/control/JSAndCSSAdder.java
@@ -47,98 +47,6 @@ public interface JSAndCSSAdder {
 	
 	public void addRequiredStaticJsFile(String jsFileName, String fileEncoding, String preAJAXAddJsCode);
 	
-	/**
-	 * adds a js file to be served in the html header to the list of required
-	 * js-files. e.g. addRequiredJsFile(MyController.class, "js/myscript.js")
-	 * where the file myscript.js must be under
-	 * "location of MyController.class"/_static/js
-	 * <p>
-	 * In full page refresh mode, the library will be included to the page
-	 * header using the standard script tags.
-	 * <p>
-	 * In AJAX mode, the library is will read the file from disk, transfer the
-	 * content via the AJAX channel and then eval() the content in the window.
-	 * <p>
-	 * In case that your script needs some values to be initialized before the
-	 * eval() happens, use the other addRequiredJsFile() for this purpose
-	 * 
-	 * @param baseClass
-	 * @param jsFileName
-	 */
-	//public void addRequiredJsFile(String jsFileName);
-
-	/**
-	 * adds a js file to be served in the html header to the list of required
-	 * js-files. e.g. addRequiredJsFile(MyController.class, "js/myscript.js")
-	 * where the file myscript.js must be under
-	 * "location of MyController.class"/_static/js
-	 * <p>
-	 * In full page refresh mode, the library will be included to the page header
-	 * using the standard script tags.
-	 * <p>
-	 * In AJAX mode, the library is will read the file from disk, transfer the
-	 * content via the AJAX channel and then eval() the content in the window. The
-	 * fileEncoding is used to read the file from disk.
-	 * <p>
-	 * In case that your script needs some values to be initialized before the
-	 * eval() happens, use the other addRequiredJsFile() for this purpose
-	 * 
-	 * @param baseClass
-	 * @param jsFileName
-	 * @param fileEncoding the encoding of the js file or NULL to use the default
-	 *          encoding (utf-8)
-	 */
-	//public void addRequiredJsFile(Class<?> baseClass, String jsFileName, String fileEncoding);
-
-	/**
-	 * adds a js file to be served in the html header to the list of required
-	 * js-files. e.g. addRequiredJsFile(MyController.class, "js/myscript.js")
-	 * where the file myscript.js must be under
-	 * "location of MyController.class"/_static/js
-	 * <p>
-	 * In full page refresh mode, the library will be included to the page header
-	 * using the standard script tags.
-	 * <p>
-	 * In AJAX mode, the library is will first eval() the content of the supplied
-	 * string evalBeforeDomReplacementJsCode, then read the file from disk,
-	 * transfere the content via the AJAX channel and then eval() the content in
-	 * the window.The fileEncoding is used to read the file from disk.
-	 * 
-	 * @param baseClass The class where the script is localted
-	 * @param jsFileName The script path, e.g. js/myscript.js
-	 * @param fileEncoding the encoding of the js file or NULL to use the default
-	 *          encoding (utf-8)
-	 * @param preAJAXAddJsCode A string containing some values to be eval()-ed
-	 *          right before the script itself is eval()-ed
-	 */
-	//public void addRequiredJsFile(Class<?> baseClass, String jsFileName, String fileEncoding, String preAJAXAddJsCode);
-
-	/**
-	 * 
-	 * @param baseClass
-	 * @param cssFileName
-	 * @param forceRemove normally, once added css files will not be removed
-	 *          anymore. However, if your css overrides default settings (e.g.
-	 *          when you have a preview css), this css must be removed as soon as
-	 *          the validate method does not require it anymore. (e.g. when you
-	 *          leave the course edit mode)
-	 * @param cssIndex position of the css in relation of the position of the
-	 *          theme. Use JSAndCSSAdder.CSS_INDEX_* variables to set this
-	 */
-	//public void addRequiredCSSFile(Class<?> baseClass, String cssFileName, boolean forceRemove, Integer cssLoadIndex);
-	
-	/**
-	 * This method will add the CSS file before the theme. use the other method to change this behaviour
-	 * @param baseClass
-	 * @param cssFileName
-	 * @param forceRemove normally, once added css files will not be removed
-	 *          anymore. However, if your css overrides default settings (e.g.
-	 *          when you have a preview css), this css must be removed as soon as
-	 *          the validate method does not require it anymore. (e.g. when you
-	 *          leave the course edit mode)
-	 */
-	//public void addRequiredCSSFile(Class<?> baseClass, String cssFileName, boolean forceRemove);
-
 	/**
 	 * 
 	 * used rather rarely, e.g. when you have a css with content which is dynamic
@@ -164,8 +72,6 @@ public interface JSAndCSSAdder {
 	
 	public void addStaticCSSPath(String cssPath);
 	
-	
-	
 	/**
 	 * 
 	 * @return true if there has been a new (never been added before) (or a deleted css which has been marked as to-be-removed) required css or js file's base since the previous call to this method, false otherwise (no new js or css libs needed)
@@ -173,7 +79,6 @@ public interface JSAndCSSAdder {
 	 */
 	public boolean finishAndCheckChange();
 	
-
 	/**
 	 * @param baseClass
 	 * @param rawHeader
@@ -201,21 +106,4 @@ public interface JSAndCSSAdder {
 	 */
 	public void requireFullPageRefresh();
 
-	/**
-	 * Get the mapper path for this class and file name, e.g. to use in a
-	 * preAJAXAddJsCode call when adding a JS script that needs to load other
-	 * scripts as well.
-	 * 
-	 * @param baseClass
-	 * @param fileName
-	 *            the name of the file or NULL to get the base path.
-	 * @return A string that represents the path of the JS file as it is used on
-	 *         a full page refresh. If fileName is null, the base path wihout
-	 *         trailing slash is returned.
-	 */
-	//public String getMappedPathFor(Class<?> baseClass, String fileName);
-
-	
-	
-	
 }
diff --git a/src/main/java/org/olat/core/gui/exception/_content/exception_page.html b/src/main/java/org/olat/core/gui/exception/_content/exception_page.html
index 6f7ee80defe81dbb0fbee5977167de4e243f1454..cd525c97f4763ae0091e54192a01bfb4675a519e 100644
--- a/src/main/java/org/olat/core/gui/exception/_content/exception_page.html
+++ b/src/main/java/org/olat/core/gui/exception/_content/exception_page.html
@@ -77,8 +77,6 @@ var o_info = new Object();
 <script type="text/javascript" src='$r.staticLink("movie/player.js")'></script>
 
 ## Always loaded
-## <link type="text/css" href='$r.staticLink("js/jquery/tagit/jquery.tagit.css")' rel="stylesheet"/>
-## <link type="text/css" href='$r.staticLink("js/jquery/uilayout/layout-default-latest.css")' rel="stylesheet"/>
 <link type="text/css" href='$r.staticLink("js/jquery/fullcalendar/fullcalendar.css")' rel="stylesheet"/>
 <link type="text/css" href='$r.staticLink("js/jquery/datatables/css/jquery.dataTables.css")' rel="stylesheet"/>
 ## FIXME:oo10 add plugin min
diff --git a/src/main/webapp/static/js/JS.README b/src/main/webapp/static/js/JS.README
index 3703dc94533f78c4976ec8e0d22fa18bb5f57cee..736b411fd6a3c71b9f95ddd06e2f2d91facc7a4c 100644
--- a/src/main/webapp/static/js/JS.README
+++ b/src/main/webapp/static/js/JS.README
@@ -23,7 +23,7 @@ it minified the 4 olat plugins for tinymce 4
   quotespliter
   
 and minified css:
-  jquery.tagit.min.css
+  bootstrap-tagsinput.css
   layout-default-latest.min.css
   fullcalendar.min.css
   dataTables.css
diff --git a/src/main/webapp/static/js/jquery/tagit/jquery.tagit.css b/src/main/webapp/static/js/jquery/tagit/jquery.tagit.css
deleted file mode 100644
index 1620ba5e6c4d11b3391bf4e7c859caee760843c6..0000000000000000000000000000000000000000
--- a/src/main/webapp/static/js/jquery/tagit/jquery.tagit.css
+++ /dev/null
@@ -1,67 +0,0 @@
-ul.tagit {
-    padding: 1px 5px;
-    overflow: auto;
-    margin-left: inherit; /* usually we don't want the regular ul margins. */
-    margin-right: inherit;
-}
-ul.tagit li {
-    display: block;
-    float: left;
-    margin: 2px 5px 2px 0;
-}
-ul.tagit li.tagit-choice {    
-    position: relative;
-    line-height: inherit;
-}
-
-ul.tagit li.tagit-choice-read-only { 
-    padding: .2em .5em .2em .5em; 
-} 
-
-ul.tagit li.tagit-choice-editable { 
-    padding: .2em 18px .2em .5em; 
-} 
-
-ul.tagit li.tagit-new {
-    padding: .25em 4px .25em 0;
-}
-
-ul.tagit li.tagit-choice a.tagit-label {
-    cursor: pointer;
-    text-decoration: none;
-}
-ul.tagit li.tagit-choice .tagit-close {
-    cursor: pointer;
-    position: absolute;
-    right: .1em;
-    top: 50%;
-    margin-top: -8px;
-    line-height: 17px;
-}
-
-/* used for some custom themes that don't need image icons */
-ul.tagit li.tagit-choice .tagit-close .text-icon {
-    display: none;
-}
-
-ul.tagit li.tagit-choice input {
-    display: block;
-    float: left;
-    margin: 2px 5px 2px 0;
-}
-ul.tagit input[type="text"] {
-    -moz-box-sizing:    border-box;
-    -webkit-box-sizing: border-box;
-    box-sizing:         border-box;
-
-    -moz-box-shadow: none;
-    -webkit-box-shadow: none;
-    box-shadow: none;
-
-    border: none;
-    margin: 0;
-    padding: 0;
-    width: inherit;
-    background-color: inherit;
-    outline: none;
-}
diff --git a/src/main/webapp/static/js/jquery/tagit/tag-it.js b/src/main/webapp/static/js/jquery/tagit/tag-it.js
deleted file mode 100644
index 9d231dfed1b272ae19b00bb470e14bb54360a953..0000000000000000000000000000000000000000
--- a/src/main/webapp/static/js/jquery/tagit/tag-it.js
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
-* jQuery UI Tag-it!
-*
-* @version v2.0 (06/2011)
-*
-* Copyright 2011, Levy Carneiro Jr.
-* Released under the MIT license.
-* http://aehlke.github.com/tag-it/LICENSE
-*
-* Homepage:
-*   http://aehlke.github.com/tag-it/
-*
-* Authors:
-*   Levy Carneiro Jr.
-*   Martin Rehfeld
-*   Tobias Schmidt
-*   Skylar Challand
-*   Alex Ehlke
-*
-* Maintainer:
-*   Alex Ehlke - Twitter: @aehlke
-*
-* Dependencies:
-*   jQuery v1.4+
-*   jQuery UI v1.8+
-*/
-(function($) {
-
-    $.widget('ui.tagit', {
-        options: {
-            allowDuplicates   : false,
-            caseSensitive     : true,
-            fieldName         : 'tags',
-            placeholderText   : null,   // Sets `placeholder` attr on input field.
-            readOnly          : false,  // Disables editing.
-            removeConfirmation: false,  // Require confirmation to remove tags.
-            tagLimit          : null,   // Max number of tags allowed (null for unlimited).
-
-            // Used for autocomplete, unless you override `autocomplete.source`.
-            availableTags     : [],
-
-            // Use to override or add any options to the autocomplete widget.
-            //
-            // By default, autocomplete.source will map to availableTags,
-            // unless overridden.
-            autocomplete: {},
-
-            // Shows autocomplete before the user even types anything.
-            showAutocompleteOnFocus: false,
-
-            // When enabled, quotes are unneccesary for inputting multi-word tags.
-            allowSpaces: false,
-
-            // The below options are for using a single field instead of several
-            // for our form values.
-            //
-            // When enabled, will use a single hidden field for the form,
-            // rather than one per tag. It will delimit tags in the field
-            // with singleFieldDelimiter.
-            //
-            // The easiest way to use singleField is to just instantiate tag-it
-            // on an INPUT element, in which case singleField is automatically
-            // set to true, and singleFieldNode is set to that element. This 
-            // way, you don't need to fiddle with these options.
-            singleField: false,
-
-            // This is just used when preloading data from the field, and for
-            // populating the field with delimited tags as the user adds them.
-            singleFieldDelimiter: ',',
-
-            // Set this to an input DOM node to use an existing form field.
-            // Any text in it will be erased on init. But it will be
-            // populated with the text of tags as they are created,
-            // delimited by singleFieldDelimiter.
-            //
-            // If this is not set, we create an input node for it,
-            // with the name given in settings.fieldName.
-            singleFieldNode: null,
-
-            // Whether to animate tag removals or not.
-            animate: true,
-
-            // Optionally set a tabindex attribute on the input that gets
-            // created for tag-it.
-            tabIndex: null,
-
-            // Event callbacks.
-            beforeTagAdded      : null,
-            afterTagAdded       : null,
-
-            beforeTagRemoved    : null,
-            afterTagRemoved     : null,
-
-            onTagClicked        : null,
-            onTagLimitExceeded  : null,
-
-
-            // DEPRECATED:
-            //
-            // /!\ These event callbacks are deprecated and WILL BE REMOVED at some
-            // point in the future. They're here for backwards-compatibility.
-            // Use the above before/after event callbacks instead.
-            onTagAdded  : null,
-            onTagRemoved: null,
-            // `autocomplete.source` is the replacement for tagSource.
-            tagSource: null
-            // Do not use the above deprecated options.
-        },
-
-        _create: function() {
-            // for handling static scoping inside callbacks
-            var that = this;
-
-            // There are 2 kinds of DOM nodes this widget can be instantiated on:
-            //     1. UL, OL, or some element containing either of these.
-            //     2. INPUT, in which case 'singleField' is overridden to true,
-            //        a UL is created and the INPUT is hidden.
-            if (this.element.is('input')) {
-                this.tagList = $('<ul></ul>').insertAfter(this.element);
-                this.options.singleField = true;
-                this.options.singleFieldNode = this.element;
-                this.element.css('display', 'none');
-            } else {
-                this.tagList = this.element.find('ul, ol').andSelf().last();
-            }
-
-            this.tagInput = $('<input type="text" />').addClass('ui-widget-content');
-
-            if (this.options.readOnly) this.tagInput.attr('disabled', 'disabled');
-
-            if (this.options.tabIndex) {
-                this.tagInput.attr('tabindex', this.options.tabIndex);
-            }
-
-            if (this.options.placeholderText) {
-                this.tagInput.attr('placeholder', this.options.placeholderText);
-            }
-
-            if (!this.options.autocomplete.source) {
-                this.options.autocomplete.source = function(search, showChoices) {
-                    var filter = search.term.toLowerCase();
-                    var choices = $.grep(this.options.availableTags, function(element) {
-                        // Only match autocomplete options that begin with the search term.
-                        // (Case insensitive.)
-                        return (element.toLowerCase().indexOf(filter) === 0);
-                    });
-                    showChoices(this._subtractArray(choices, this.assignedTags()));
-                };
-            }
-
-            if (this.options.showAutocompleteOnFocus) {
-                this.tagInput.focus(function(event, ui) {
-                    that._showAutocomplete();
-                });
-
-                if (typeof this.options.autocomplete.minLength === 'undefined') {
-                    this.options.autocomplete.minLength = 0;
-                }
-            }
-
-            // Bind autocomplete.source callback functions to this context.
-            if ($.isFunction(this.options.autocomplete.source)) {
-                this.options.autocomplete.source = $.proxy(this.options.autocomplete.source, this);
-            }
-
-            // DEPRECATED.
-            if ($.isFunction(this.options.tagSource)) {
-                this.options.tagSource = $.proxy(this.options.tagSource, this);
-            }
-
-            this.tagList
-                .addClass('tagit')
-                .addClass('ui-widget ui-widget-content ui-corner-all')
-                // Create the input field.
-                .append($('<li class="tagit-new"></li>').append(this.tagInput))
-                .click(function(e) {
-                    var target = $(e.target);
-                    if (target.hasClass('tagit-label')) {
-                        var tag = target.closest('.tagit-choice');
-                        if (!tag.hasClass('removed')) {
-                            that._trigger('onTagClicked', e, {tag: tag, tagLabel: that.tagLabel(tag)});
-                        }
-                    } else {
-                        // Sets the focus() to the input field, if the user
-                        // clicks anywhere inside the UL. This is needed
-                        // because the input field needs to be of a small size.
-                        that.tagInput.focus();
-                    }
-                });
-
-            // Single field support.
-            var addedExistingFromSingleFieldNode = false;
-            if (this.options.singleField) {
-                if (this.options.singleFieldNode) {
-                    // Add existing tags from the input field.
-                    var node = $(this.options.singleFieldNode);
-                    var tags = node.val().split(this.options.singleFieldDelimiter);
-                    node.val('');
-                    $.each(tags, function(index, tag) {
-                        that.createTag(tag, null, true);
-                        addedExistingFromSingleFieldNode = true;
-                    });
-                } else {
-                    // Create our single field input after our list.
-                    this.options.singleFieldNode = $('<input type="hidden" style="display:none;" value="" name="' + this.options.fieldName + '" />');
-                    this.tagList.after(this.options.singleFieldNode);
-                }
-            }
-
-            // Add existing tags from the list, if any.
-            if (!addedExistingFromSingleFieldNode) {
-                this.tagList.children('li').each(function() {
-                    if (!$(this).hasClass('tagit-new')) {
-                        that.createTag($(this).text(), $(this).attr('class'), true);
-                        $(this).remove();
-                    }
-                });
-            }
-
-            // Events.
-            this.tagInput
-                .keydown(function(event) {
-                    // Backspace is not detected within a keypress, so it must use keydown.
-                    if (event.which == $.ui.keyCode.BACKSPACE && that.tagInput.val() === '') {
-                        var tag = that._lastTag();
-                        if (!that.options.removeConfirmation || tag.hasClass('remove')) {
-                            // When backspace is pressed, the last tag is deleted.
-                            that.removeTag(tag);
-                        } else if (that.options.removeConfirmation) {
-                            tag.addClass('remove ui-state-highlight');
-                        }
-                    } else if (that.options.removeConfirmation) {
-                        that._lastTag().removeClass('remove ui-state-highlight');
-                    }
-
-                    // Comma/Space/Enter are all valid delimiters for new tags,
-                    // except when there is an open quote or if setting allowSpaces = true.
-                    // Tab will also create a tag, unless the tag input is empty, 
-                    // in which case it isn't caught.
-                    if (
-                        event.which === $.ui.keyCode.COMMA ||
-                        event.which === $.ui.keyCode.ENTER ||
-                        (
-                            event.which == $.ui.keyCode.TAB &&
-                            that.tagInput.val() !== ''
-                        ) ||
-                        (
-                            event.which == $.ui.keyCode.SPACE &&
-                            that.options.allowSpaces !== true &&
-                            (
-                                $.trim(that.tagInput.val()).replace( /^s*/, '' ).charAt(0) != '"' ||
-                                (
-                                    $.trim(that.tagInput.val()).charAt(0) == '"' &&
-                                    $.trim(that.tagInput.val()).charAt($.trim(that.tagInput.val()).length - 1) == '"' &&
-                                    $.trim(that.tagInput.val()).length - 1 !== 0
-                                )
-                            )
-                        )
-                    ) {
-                        // Enter submits the form if there's no text in the input.
-                        if (!(event.which === $.ui.keyCode.ENTER && that.tagInput.val() === '')) {
-                            event.preventDefault();
-                        }
-
-                        that.createTag(that._cleanedInput());
-
-                        // The autocomplete doesn't close automatically when TAB is pressed.
-                        // So let's ensure that it closes.
-                        that.tagInput.autocomplete('close');
-                    }
-                }).blur(function(e){
-                    // Create a tag when the element loses focus.
-                    // If autocomplete is enabled and suggestion was clicked, don't add it.
-                    if (!that.tagInput.data('autocomplete-open')) {
-                        that.createTag(that._cleanedInput());
-                    }
-                });
-
-            // Autocomplete.
-            if (this.options.availableTags || this.options.tagSource || this.options.autocomplete.source) {
-                var autocompleteOptions = {
-                    select: function(event, ui) {
-                        that.createTag(ui.item.value);
-                        // Preventing the tag input to be updated with the chosen value.
-                        return false;
-                    }
-                };
-                $.extend(autocompleteOptions, this.options.autocomplete);
-
-                // tagSource is deprecated, but takes precedence here since autocomplete.source is set by default,
-                // while tagSource is left null by default.
-                autocompleteOptions.source = this.options.tagSource || autocompleteOptions.source;
-
-                this.tagInput.autocomplete(autocompleteOptions).bind('autocompleteopen', function(event, ui) {
-                    that.tagInput.data('autocomplete-open', true);
-                }).bind('autocompleteclose', function(event, ui) {
-                    that.tagInput.data('autocomplete-open', false)
-                });
-            }
-        },
-
-        _cleanedInput: function() {
-            // Returns the contents of the tag input, cleaned and ready to be passed to createTag
-            return $.trim(this.tagInput.val().replace(/^"(.*)"$/, '$1'));
-        },
-
-        _lastTag: function() {
-            return this.tagList.find('.tagit-choice:last:not(.removed)');
-        },
-
-        _tags: function() {
-            return this.tagList.find('.tagit-choice:not(.removed)');
-        },
-
-        assignedTags: function() {
-            // Returns an array of tag string values
-            var that = this;
-            var tags = [];
-            if (this.options.singleField) {
-                tags = $(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter);
-                if (tags[0] === '') {
-                    tags = [];
-                }
-            } else {
-                this._tags().each(function() {
-                    tags.push(that.tagLabel(this));
-                });
-            }
-            return tags;
-        },
-
-        _updateSingleTagsField: function(tags) {
-            // Takes a list of tag string values, updates this.options.singleFieldNode.val to the tags delimited by this.options.singleFieldDelimiter
-            $(this.options.singleFieldNode).val(tags.join(this.options.singleFieldDelimiter)).trigger('change');
-        },
-
-        _subtractArray: function(a1, a2) {
-            var result = [];
-            for (var i = 0; i < a1.length; i++) {
-                if ($.inArray(a1[i], a2) == -1) {
-                    result.push(a1[i]);
-                }
-            }
-            return result;
-        },
-
-        tagLabel: function(tag) {
-            // Returns the tag's string label.
-            if (this.options.singleField) {
-                return $(tag).find('.tagit-label:first').text();
-            } else {
-                return $(tag).find('input:first').val();
-            }
-        },
-
-        _showAutocomplete: function() {
-            this.tagInput.autocomplete('search', '');
-        },
-
-        _findTagByLabel: function(name) {
-            var that = this;
-            var tag = null;
-            this._tags().each(function(i) {
-                if (that._formatStr(name) == that._formatStr(that.tagLabel(this))) {
-                    tag = $(this);
-                    return false;
-                }
-            });
-            return tag;
-        },
-
-        _isNew: function(name) {
-            return !this._findTagByLabel(name);
-        },
-
-        _formatStr: function(str) {
-            if (this.options.caseSensitive) {
-                return str;
-            }
-            return $.trim(str.toLowerCase());
-        },
-
-        _effectExists: function(name) {
-            return Boolean($.effects && ($.effects[name] || ($.effects.effect && $.effects.effect[name])));
-        },
-
-        createTag: function(value, additionalClass, duringInitialization) {
-            var that = this;
-
-            value = $.trim(value);
-
-            if (value === '') {
-                return false;
-            }
-
-            if (!this.options.allowDuplicates && !this._isNew(value)) {
-                var existingTag = this._findTagByLabel(value);
-                if (this._trigger('onTagExists', null, {
-                    existingTag: existingTag,
-                    duringInitialization: duringInitialization
-                }) !== false) {
-                    if (this._effectExists('highlight')) {
-                        existingTag.effect('highlight');
-                    }
-                }
-                return false;
-            }
-
-            if (this.options.tagLimit && this._tags().length >= this.options.tagLimit) {
-                this._trigger('onTagLimitExceeded', null, {duringInitialization: duringInitialization});
-                return false;
-            }
-
-            var label = $(this.options.onTagClicked ? '<a class="tagit-label"></a>' : '<span class="tagit-label"></span>').text(value);
-
-            // Create tag.
-            var tag = $('<li></li>')
-                .addClass('tagit-choice ui-widget-content ui-state-default ui-corner-all')
-                .addClass(additionalClass)
-                .append(label);
-
-            if (this.options.readOnly){
-                tag.addClass('tagit-choice-read-only');
-            } else {
-                tag.addClass('tagit-choice-editable');
-                // Button for removing the tag.
-                var removeTagIcon = $('<span></span>')
-                    .addClass('ui-icon ui-icon-close');
-                var removeTag = $('<a><span class="text-icon">\xd7</span></a>') // \xd7 is an X
-                    .addClass('tagit-close')
-                    .append(removeTagIcon)
-                    .click(function(e) {
-                        // Removes a tag when the little 'x' is clicked.
-                        that.removeTag(tag);
-                    });
-                tag.append(removeTag);
-            }
-
-            // Unless options.singleField is set, each tag has a hidden input field inline.
-            if (!this.options.singleField) {
-                var escapedValue = label.html();
-                tag.append('<input type="hidden" style="display:none;" value="' + escapedValue + '" name="' + this.options.fieldName + '" />');
-            }
-
-            if (this._trigger('beforeTagAdded', null, {
-                tag: tag,
-                tagLabel: this.tagLabel(tag),
-                duringInitialization: duringInitialization
-            }) === false) {
-                return;
-            }
-
-            if (this.options.singleField) {
-                var tags = this.assignedTags();
-                tags.push(value);
-                this._updateSingleTagsField(tags);
-            }
-
-            // DEPRECATED.
-            this._trigger('onTagAdded', null, tag);
-
-            this.tagInput.val('');
-
-            // Insert tag.
-            this.tagInput.parent().before(tag);
-
-            this._trigger('afterTagAdded', null, {
-                tag: tag,
-                tagLabel: this.tagLabel(tag),
-                duringInitialization: duringInitialization
-            });
-
-            if (this.options.showAutocompleteOnFocus && !duringInitialization) {
-                setTimeout(function () { that._showAutocomplete(); }, 0);
-            }
-        },
-
-        removeTag: function(tag, animate) {
-            animate = typeof animate === 'undefined' ? this.options.animate : animate;
-
-            tag = $(tag);
-
-            // DEPRECATED.
-            this._trigger('onTagRemoved', null, tag);
-
-            if (this._trigger('beforeTagRemoved', null, {tag: tag, tagLabel: this.tagLabel(tag)}) === false) {
-                return;
-            }
-
-            if (this.options.singleField) {
-                var tags = this.assignedTags();
-                var removedTagLabel = this.tagLabel(tag);
-                tags = $.grep(tags, function(el){
-                    return el != removedTagLabel;
-                });
-                this._updateSingleTagsField(tags);
-            }
-
-            if (animate) {
-                tag.addClass('removed'); // Excludes this tag from _tags.
-                var hide_args = this._effectExists('blind') ? ['blind', {direction: 'horizontal'}, 'fast'] : ['fast'];
-
-                hide_args.push(function() {
-                    tag.remove();
-                });
-
-                tag.fadeOut('fast').hide.apply(tag, hide_args).dequeue();
-            } else {
-                tag.remove();
-            }
-
-            this._trigger('afterTagRemoved', null, {tag: tag, tagLabel: this.tagLabel(tag)});
-        },
-
-        removeTagByLabel: function(tagLabel, animate) {
-            var toRemove = this._findTagByLabel(tagLabel);
-            if (!toRemove) {
-                throw "No such tag exists with the name '" + tagLabel + "'";
-            }
-            this.removeTag(toRemove, animate);
-        },
-
-        removeAll: function() {
-            // Removes all tags.
-            var that = this;
-            this._tags().each(function(index, tag) {
-                that.removeTag(tag, false);
-            });
-        }
-
-    });
-})(jQuery);
-
diff --git a/src/main/webapp/static/js/jquery/tagit/tag-it.min.js b/src/main/webapp/static/js/jquery/tagit/tag-it.min.js
deleted file mode 100644
index 3fdf3ce05e3febeb9a707aa507d20a8a7b238e7c..0000000000000000000000000000000000000000
--- a/src/main/webapp/static/js/jquery/tagit/tag-it.min.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(function(b){b.widget("ui.tagit",{options:{allowDuplicates:!1,caseSensitive:!0,fieldName:"tags",placeholderText:null,readOnly:!1,removeConfirmation:!1,tagLimit:null,availableTags:[],autocomplete:{},showAutocompleteOnFocus:!1,allowSpaces:!1,singleField:!1,singleFieldDelimiter:",",singleFieldNode:null,animate:!0,tabIndex:null,beforeTagAdded:null,afterTagAdded:null,beforeTagRemoved:null,afterTagRemoved:null,onTagClicked:null,onTagLimitExceeded:null,onTagAdded:null,onTagRemoved:null,tagSource:null},_create:function(){var a=
-this;this.element.is("input")?(this.tagList=b("<ul></ul>").insertAfter(this.element),this.options.singleField=!0,this.options.singleFieldNode=this.element,this.element.css("display","none")):this.tagList=this.element.find("ul, ol").andSelf().last();this.tagInput=b('<input type="text" />').addClass("ui-widget-content");this.options.readOnly&&this.tagInput.attr("disabled","disabled");this.options.tabIndex&&this.tagInput.attr("tabindex",this.options.tabIndex);this.options.placeholderText&&this.tagInput.attr("placeholder",
-this.options.placeholderText);this.options.autocomplete.source||(this.options.autocomplete.source=function(a,c){var d=a.term.toLowerCase(),e=b.grep(this.options.availableTags,function(a){return 0===a.toLowerCase().indexOf(d)});c(this._subtractArray(e,this.assignedTags()))});this.options.showAutocompleteOnFocus&&(this.tagInput.focus(function(){a._showAutocomplete()}),"undefined"===typeof this.options.autocomplete.minLength&&(this.options.autocomplete.minLength=0));b.isFunction(this.options.autocomplete.source)&&
-(this.options.autocomplete.source=b.proxy(this.options.autocomplete.source,this));b.isFunction(this.options.tagSource)&&(this.options.tagSource=b.proxy(this.options.tagSource,this));this.tagList.addClass("tagit").addClass("ui-widget ui-widget-content ui-corner-all").append(b('<li class="tagit-new"></li>').append(this.tagInput)).click(function(c){var d=b(c.target);d.hasClass("tagit-label")?(d=d.closest(".tagit-choice"),d.hasClass("removed")||a._trigger("onTagClicked",c,{tag:d,tagLabel:a.tagLabel(d)})):
-a.tagInput.focus()});var d=!1;if(this.options.singleField)if(this.options.singleFieldNode){var c=b(this.options.singleFieldNode),e=c.val().split(this.options.singleFieldDelimiter);c.val("");b.each(e,function(b,c){a.createTag(c,null,!0);d=!0})}else this.options.singleFieldNode=b('<input type="hidden" style="display:none;" value="" name="'+this.options.fieldName+'" />'),this.tagList.after(this.options.singleFieldNode);d||this.tagList.children("li").each(function(){b(this).hasClass("tagit-new")||(a.createTag(b(this).text(),
-b(this).attr("class"),!0),b(this).remove())});this.tagInput.keydown(function(c){if(c.which==b.ui.keyCode.BACKSPACE&&""===a.tagInput.val()){var d=a._lastTag();!a.options.removeConfirmation||d.hasClass("remove")?a.removeTag(d):a.options.removeConfirmation&&d.addClass("remove ui-state-highlight")}else a.options.removeConfirmation&&a._lastTag().removeClass("remove ui-state-highlight");if(c.which===b.ui.keyCode.COMMA||c.which===b.ui.keyCode.ENTER||c.which==b.ui.keyCode.TAB&&""!==a.tagInput.val()||c.which==
-b.ui.keyCode.SPACE&&!0!==a.options.allowSpaces&&('"'!=b.trim(a.tagInput.val()).replace(/^s*/,"").charAt(0)||'"'==b.trim(a.tagInput.val()).charAt(0)&&'"'==b.trim(a.tagInput.val()).charAt(b.trim(a.tagInput.val()).length-1)&&0!==b.trim(a.tagInput.val()).length-1))c.which===b.ui.keyCode.ENTER&&""===a.tagInput.val()||c.preventDefault(),a.createTag(a._cleanedInput()),a.tagInput.autocomplete("close")}).blur(function(){a.tagInput.data("autocomplete-open")||a.createTag(a._cleanedInput())});if(this.options.availableTags||
-this.options.tagSource||this.options.autocomplete.source)c={select:function(b,c){a.createTag(c.item.value);return!1}},b.extend(c,this.options.autocomplete),c.source=this.options.tagSource||c.source,this.tagInput.autocomplete(c).bind("autocompleteopen",function(){a.tagInput.data("autocomplete-open",!0)}).bind("autocompleteclose",function(){a.tagInput.data("autocomplete-open",!1)})},_cleanedInput:function(){return b.trim(this.tagInput.val().replace(/^"(.*)"$/,"$1"))},_lastTag:function(){return this.tagList.find(".tagit-choice:last:not(.removed)")},
-_tags:function(){return this.tagList.find(".tagit-choice:not(.removed)")},assignedTags:function(){var a=this,d=[];this.options.singleField?(d=b(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter),""===d[0]&&(d=[])):this._tags().each(function(){d.push(a.tagLabel(this))});return d},_updateSingleTagsField:function(a){b(this.options.singleFieldNode).val(a.join(this.options.singleFieldDelimiter)).trigger("change")},_subtractArray:function(a,d){for(var c=[],e=0;e<a.length;e++)-1==
-b.inArray(a[e],d)&&c.push(a[e]);return c},tagLabel:function(a){return this.options.singleField?b(a).find(".tagit-label:first").text():b(a).find("input:first").val()},_showAutocomplete:function(){this.tagInput.autocomplete("search","")},_findTagByLabel:function(a){var d=this,c=null;this._tags().each(function(){if(d._formatStr(a)==d._formatStr(d.tagLabel(this)))return c=b(this),!1});return c},_isNew:function(a){return!this._findTagByLabel(a)},_formatStr:function(a){return this.options.caseSensitive?
-a:b.trim(a.toLowerCase())},_effectExists:function(a){return Boolean(b.effects&&(b.effects[a]||b.effects.effect&&b.effects.effect[a]))},createTag:function(a,d,c){var e=this;a=b.trim(a);if(""===a)return!1;if(!this.options.allowDuplicates&&!this._isNew(a))return a=this._findTagByLabel(a),!1!==this._trigger("onTagExists",null,{existingTag:a,duringInitialization:c})&&this._effectExists("highlight")&&a.effect("highlight"),!1;if(this.options.tagLimit&&this._tags().length>=this.options.tagLimit)return this._trigger("onTagLimitExceeded",
-null,{duringInitialization:c}),!1;var g=b(this.options.onTagClicked?'<a class="tagit-label"></a>':'<span class="tagit-label"></span>').text(a),f=b("<li></li>").addClass("tagit-choice ui-widget-content ui-state-default ui-corner-all").addClass(d).append(g);this.options.readOnly?f.addClass("tagit-choice-read-only"):(f.addClass("tagit-choice-editable"),d=b("<span></span>").addClass("ui-icon ui-icon-close"),d=b('<a><span class="text-icon">\u00d7</span></a>').addClass("tagit-close").append(d).click(function(){e.removeTag(f)}),
-f.append(d));this.options.singleField||(g=g.html(),f.append('<input type="hidden" style="display:none;" value="'+g+'" name="'+this.options.fieldName+'" />'));!1!==this._trigger("beforeTagAdded",null,{tag:f,tagLabel:this.tagLabel(f),duringInitialization:c})&&(this.options.singleField&&(g=this.assignedTags(),g.push(a),this._updateSingleTagsField(g)),this._trigger("onTagAdded",null,f),this.tagInput.val(""),this.tagInput.parent().before(f),this._trigger("afterTagAdded",null,{tag:f,tagLabel:this.tagLabel(f),
-duringInitialization:c}),this.options.showAutocompleteOnFocus&&!c&&setTimeout(function(){e._showAutocomplete()},0))},removeTag:function(a,d){d="undefined"===typeof d?this.options.animate:d;a=b(a);this._trigger("onTagRemoved",null,a);if(!1!==this._trigger("beforeTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})){if(this.options.singleField){var c=this.assignedTags(),e=this.tagLabel(a),c=b.grep(c,function(a){return a!=e});this._updateSingleTagsField(c)}d?(a.addClass("removed"),c=this._effectExists("blind")?
-["blind",{direction:"horizontal"},"fast"]:["fast"],c.push(function(){a.remove()}),a.fadeOut("fast").hide.apply(a,c).dequeue()):a.remove();this._trigger("afterTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})}},removeTagByLabel:function(a,b){var c=this._findTagByLabel(a);if(!c)throw"No such tag exists with the name '"+a+"'";this.removeTag(c,b)},removeAll:function(){var a=this;this._tags().each(function(b,c){a.removeTag(c,!1)})}})})(jQuery);
diff --git a/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.css b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.css
new file mode 100644
index 0000000000000000000000000000000000000000..98cfa7f3c1db344bcde8ea709c0170c16adaa6b1
--- /dev/null
+++ b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.css
@@ -0,0 +1,45 @@
+.bootstrap-tagsinput {
+  background-color: #fff;
+  border: 1px solid #ccc;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  display: inline-block;
+  padding: 4px 6px;
+  margin-bottom: 10px;
+  color: #555;
+  vertical-align: middle;
+  border-radius: 4px;
+  max-width: 100%;
+  line-height: 22px;
+}
+.bootstrap-tagsinput input {
+  border: none;
+  box-shadow: none;
+  outline: none;
+  background-color: transparent;
+  padding: 0;
+  margin: 0;
+  width: auto !important;
+  max-width: inherit;
+}
+.bootstrap-tagsinput input:focus {
+  border: none;
+  box-shadow: none;
+}
+.bootstrap-tagsinput .tag {
+  margin-right: 2px;
+  color: white;
+}
+.bootstrap-tagsinput .tag [data-role="remove"] {
+  margin-left: 8px;
+  cursor: pointer;
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:after {
+  content: "x";
+  padding: 0px 2px;
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:hover {
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
diff --git a/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.js b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c97aceeae4f051241956821dc3b294207fe8504
--- /dev/null
+++ b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.js
@@ -0,0 +1,503 @@
+(function ($) {
+  "use strict";
+
+  var defaultOptions = {
+    tagClass: function(item) {
+      return 'label label-info';
+    },
+    itemValue: function(item) {
+      return item ? item.toString() : item;
+    },
+    itemText: function(item) {
+      return this.itemValue(item);
+    },
+    freeInput: true,
+    maxTags: undefined,
+    confirmKeys: [13],
+    onTagExists: function(item, $tag) {
+      $tag.hide().fadeIn();
+    }
+  };
+
+  /**
+   * Constructor function
+   */
+  function TagsInput(element, options) {
+    this.itemsArray = [];
+
+    this.$element = $(element);
+    this.$element.hide();
+
+    this.isSelect = (element.tagName === 'SELECT');
+    this.multiple = (this.isSelect && element.hasAttribute('multiple'));
+    this.objectItems = options && options.itemValue;
+    this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
+    this.inputSize = Math.max(1, this.placeholderText.length);
+
+    this.$container = $('<div class="bootstrap-tagsinput"></div>');
+    this.$input = $('<input size="' + this.inputSize + '" type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
+
+    this.$element.after(this.$container);
+
+    this.build(options);
+  }
+
+  TagsInput.prototype = {
+    constructor: TagsInput,
+
+    /**
+     * Adds the given item as a new tag. Pass true to dontPushVal to prevent
+     * updating the elements val()
+     */
+    add: function(item, dontPushVal) {
+      var self = this;
+
+      if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
+        return;
+
+      // Ignore falsey values, except false
+      if (item !== false && !item)
+        return;
+
+      // Throw an error when trying to add an object while the itemValue option was not set
+      if (typeof item === "object" && !self.objectItems)
+        throw("Can't add objects when itemValue option is not set");
+
+      // Ignore strings only containg whitespace
+      if (item.toString().match(/^\s*$/))
+        return;
+
+      // If SELECT but not multiple, remove current tag
+      if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
+        self.remove(self.itemsArray[0]);
+
+      if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
+        var items = item.split(',');
+        if (items.length > 1) {
+          for (var i = 0; i < items.length; i++) {
+            this.add(items[i], true);
+          }
+
+          if (!dontPushVal)
+            self.pushVal();
+          return;
+        }
+      }
+
+      var itemValue = self.options.itemValue(item),
+          itemText = self.options.itemText(item),
+          tagClass = self.options.tagClass(item);
+
+      // Ignore items allready added
+      var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
+      if (existing) {
+        // Invoke onTagExists
+        if (self.options.onTagExists) {
+          var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
+          self.options.onTagExists(item, $existingTag);
+        }
+        return;
+      }
+
+      // register item in internal array and map
+      self.itemsArray.push(item);
+
+      // add a tag element
+      var $tag = $('<span class="tag ' + htmlEncode(tagClass) + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
+      $tag.data('item', item);
+      self.findInputWrapper().before($tag);
+      $tag.after(' ');
+
+      // add <option /> if item represents a value not present in one of the <select />'s options
+      if (self.isSelect && !$('option[value="' + escape(itemValue) + '"]',self.$element)[0]) {
+        var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
+        $option.data('item', item);
+        $option.attr('value', itemValue);
+        self.$element.append($option);
+      }
+
+      if (!dontPushVal)
+        self.pushVal();
+
+      // Add class when reached maxTags
+      if (self.options.maxTags === self.itemsArray.length)
+        self.$container.addClass('bootstrap-tagsinput-max');
+
+      self.$element.trigger($.Event('itemAdded', { item: item }));
+    },
+
+    /**
+     * Removes the given item. Pass true to dontPushVal to prevent updating the
+     * elements val()
+     */
+    remove: function(item, dontPushVal) {
+      var self = this;
+
+      if (self.objectItems) {
+        if (typeof item === "object")
+          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  self.options.itemValue(item); } )[0];
+        else
+          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  item; } )[0];
+      }
+
+      if (item) {
+        $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
+        $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
+        self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
+      }
+
+      if (!dontPushVal)
+        self.pushVal();
+
+      // Remove class when reached maxTags
+      if (self.options.maxTags > self.itemsArray.length)
+        self.$container.removeClass('bootstrap-tagsinput-max');
+
+      self.$element.trigger($.Event('itemRemoved',  { item: item }));
+    },
+
+    /**
+     * Removes all items
+     */
+    removeAll: function() {
+      var self = this;
+
+      $('.tag', self.$container).remove();
+      $('option', self.$element).remove();
+
+      while(self.itemsArray.length > 0)
+        self.itemsArray.pop();
+
+      self.pushVal();
+
+      if (self.options.maxTags && !this.isEnabled())
+        this.enable();
+    },
+
+    /**
+     * Refreshes the tags so they match the text/value of their corresponding
+     * item.
+     */
+    refresh: function() {
+      var self = this;
+      $('.tag', self.$container).each(function() {
+        var $tag = $(this),
+            item = $tag.data('item'),
+            itemValue = self.options.itemValue(item),
+            itemText = self.options.itemText(item),
+            tagClass = self.options.tagClass(item);
+
+          // Update tag's class and inner text
+          $tag.attr('class', null);
+          $tag.addClass('tag ' + htmlEncode(tagClass));
+          $tag.contents().filter(function() {
+            return this.nodeType == 3;
+          })[0].nodeValue = htmlEncode(itemText);
+
+          if (self.isSelect) {
+            var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
+            option.attr('value', itemValue);
+          }
+      });
+    },
+
+    /**
+     * Returns the items added as tags
+     */
+    items: function() {
+      return this.itemsArray;
+    },
+
+    /**
+     * Assembly value by retrieving the value of each item, and set it on the
+     * element. 
+     */
+    pushVal: function() {
+      var self = this,
+          val = $.map(self.items(), function(item) {
+            return self.options.itemValue(item).toString();
+          });
+
+      self.$element.val(val, true).trigger('change');
+    },
+
+    /**
+     * Initializes the tags input behaviour on the element
+     */
+    build: function(options) {
+      var self = this;
+
+      self.options = $.extend({}, defaultOptions, options);
+      var typeahead = self.options.typeahead || {};
+
+      // When itemValue is set, freeInput should always be false
+      if (self.objectItems)
+        self.options.freeInput = false;
+
+      makeOptionItemFunction(self.options, 'itemValue');
+      makeOptionItemFunction(self.options, 'itemText');
+      makeOptionItemFunction(self.options, 'tagClass');
+
+      // for backwards compatibility, self.options.source is deprecated
+      if (self.options.source)
+        typeahead.source = self.options.source;
+
+      if (typeahead.source && $.fn.typeahead) {
+        makeOptionFunction(typeahead, 'source');
+
+        self.$input.typeahead({
+          source: function (query, process) {
+            function processItems(items) {
+              var texts = [];
+
+              for (var i = 0; i < items.length; i++) {
+                var text = self.options.itemText(items[i]);
+                map[text] = items[i];
+                texts.push(text);
+              }
+              process(texts);
+            }
+
+            this.map = {};
+            var map = this.map,
+                data = typeahead.source(query);
+
+            if ($.isFunction(data.success)) {
+              // support for Angular promises
+              data.success(processItems);
+            } else {
+              // support for functions and jquery promises
+              $.when(data)
+               .then(processItems);
+            }
+          },
+          updater: function (text) {
+            self.add(this.map[text]);
+          },
+          matcher: function (text) {
+            return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
+          },
+          sorter: function (texts) {
+            return texts.sort();
+          },
+          highlighter: function (text) {
+            var regex = new RegExp( '(' + this.query + ')', 'gi' );
+            return text.replace( regex, "<strong>$1</strong>" );
+          }
+        });
+      }
+
+      self.$container.on('click', $.proxy(function(event) {
+        self.$input.focus();
+      }, self));
+
+      self.$container.on('keydown', 'input', $.proxy(function(event) {
+        var $input = $(event.target),
+            $inputWrapper = self.findInputWrapper();
+
+        switch (event.which) {
+          // BACKSPACE
+          case 8:
+            if (doGetCaretPosition($input[0]) === 0) {
+              var prev = $inputWrapper.prev();
+              if (prev) {
+                self.remove(prev.data('item'));
+              }
+            }
+            break;
+
+          // DELETE
+          case 46:
+            if (doGetCaretPosition($input[0]) === 0) {
+              var next = $inputWrapper.next();
+              if (next) {
+                self.remove(next.data('item'));
+              }
+            }
+            break;
+
+          // LEFT ARROW
+          case 37:
+            // Try to move the input before the previous tag
+            var $prevTag = $inputWrapper.prev();
+            if ($input.val().length === 0 && $prevTag[0]) {
+              $prevTag.before($inputWrapper);
+              $input.focus();
+            }
+            break;
+          // RIGHT ARROW
+          case 39:
+            // Try to move the input after the next tag
+            var $nextTag = $inputWrapper.next();
+            if ($input.val().length === 0 && $nextTag[0]) {
+              $nextTag.after($inputWrapper);
+              $input.focus();
+            }
+            break;
+         default:
+            // When key corresponds one of the confirmKeys, add current input
+            // as a new tag
+            if (self.options.freeInput && $.inArray(event.which, self.options.confirmKeys) >= 0) {
+              self.add($input.val());
+              $input.val('');
+              event.preventDefault();
+            }
+        }
+
+        // Reset internal input's size
+        $input.attr('size', Math.max(this.inputSize, $input.val().length));
+      }, self));
+
+      // Remove icon clicked
+      self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
+        self.remove($(event.target).closest('.tag').data('item'));
+      }, self));
+
+      // Only add existing value as tags when using strings as tags
+      if (self.options.itemValue === defaultOptions.itemValue) {
+        if (self.$element[0].tagName === 'INPUT') {
+            self.add(self.$element.val());
+        } else {
+          $('option', self.$element).each(function() {
+            self.add($(this).attr('value'), true);
+          });
+        }
+      }
+    },
+
+    /**
+     * Removes all tagsinput behaviour and unregsiter all event handlers
+     */
+    destroy: function() {
+      var self = this;
+
+      // Unbind events
+      self.$container.off('keypress', 'input');
+      self.$container.off('click', '[role=remove]');
+
+      self.$container.remove();
+      self.$element.removeData('tagsinput');
+      self.$element.show();
+    },
+
+    /**
+     * Sets focus on the tagsinput 
+     */
+    focus: function() {
+      this.$input.focus();
+    },
+
+    /**
+     * Returns the internal input element
+     */
+    input: function() {
+      return this.$input;
+    },
+
+    /**
+     * Returns the element which is wrapped around the internal input. This
+     * is normally the $container, but typeahead.js moves the $input element.
+     */
+    findInputWrapper: function() {
+      var elt = this.$input[0],
+          container = this.$container[0];
+      while(elt && elt.parentNode !== container)
+        elt = elt.parentNode;
+
+      return $(elt);
+    }
+  };
+
+  /**
+   * Register JQuery plugin
+   */
+  $.fn.tagsinput = function(arg1, arg2) {
+    var results = [];
+
+    this.each(function() {
+      var tagsinput = $(this).data('tagsinput');
+
+      // Initialize a new tags input
+      if (!tagsinput) {
+        tagsinput = new TagsInput(this, arg1);
+        $(this).data('tagsinput', tagsinput);
+        results.push(tagsinput);
+
+        if (this.tagName === 'SELECT') {
+          $('option', $(this)).attr('selected', 'selected');
+        }
+
+        // Init tags from $(this).val()
+        $(this).val($(this).val());
+      } else {
+        // Invoke function on existing tags input
+        var retVal = tagsinput[arg1](arg2);
+        if (retVal !== undefined)
+          results.push(retVal);
+      }
+    });
+
+    if ( typeof arg1 == 'string') {
+      // Return the results from the invoked function calls
+      return results.length > 1 ? results : results[0];
+    } else {
+      return results;
+    }
+  };
+
+  $.fn.tagsinput.Constructor = TagsInput;
+  
+  /**
+   * Most options support both a string or number as well as a function as 
+   * option value. This function makes sure that the option with the given
+   * key in the given options is wrapped in a function
+   */
+  function makeOptionItemFunction(options, key) {
+    if (typeof options[key] !== 'function') {
+      var propertyName = options[key];
+      options[key] = function(item) { return item[propertyName]; };
+    }
+  }
+  function makeOptionFunction(options, key) {
+    if (typeof options[key] !== 'function') {
+      var value = options[key];
+      options[key] = function() { return value; };
+    }
+  }
+  /**
+   * HtmlEncodes the given value
+   */
+  var htmlEncodeContainer = $('<div />');
+  function htmlEncode(value) {
+    if (value) {
+      return htmlEncodeContainer.text(value).html();
+    } else {
+      return '';
+    }
+  }
+
+  /**
+   * Returns the position of the caret in the given input field
+   * http://flightschool.acylt.com/devnotes/caret-position-woes/
+   */
+  function doGetCaretPosition(oField) {
+    var iCaretPos = 0;
+    if (document.selection) {
+      oField.focus ();
+      var oSel = document.selection.createRange();
+      oSel.moveStart ('character', -oField.value.length);
+      iCaretPos = oSel.text.length;
+    } else if (oField.selectionStart || oField.selectionStart == '0') {
+      iCaretPos = oField.selectionStart;
+    }
+    return (iCaretPos);
+  }
+
+  /**
+   * Initialize tagsinput behaviour on inputs and selects which have
+   * data-role=tagsinput
+   */
+  $(function() {
+    $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
+  });
+})(window.jQuery);
diff --git a/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.min.js b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..85635835537d06c7b1c79f78452a8deb8a60cb3f
--- /dev/null
+++ b/src/main/webapp/static/js/jquery/tagsinput/bootstrap-tagsinput.min.js
@@ -0,0 +1,5 @@
+/*
+ * bootstrap-tagsinput v0.3.9 by Tim Schlechter
+ * 
+ */
+!function(a){"use strict";function b(b,c){this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('<div class="bootstrap-tagsinput"></div>'),this.$input=a('<input size="'+this.inputSize+'" type="text" placeholder="'+this.placeholderText+'"/>').appendTo(this.$container),this.$element.after(this.$container),this.build(c)}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?h.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}var g={tagClass:function(){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},freeInput:!0,maxTags:void 0,confirmKeys:[13],onTagExists:function(a,b){b.hide().fadeIn()}};b.prototype={constructor:b,add:function(b,c){var d=this;if(!(d.options.maxTags&&d.itemsArray.length>=d.options.maxTags||b!==!1&&!b)){if("object"==typeof b&&!d.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(d.isSelect&&!d.multiple&&d.itemsArray.length>0&&d.remove(d.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var f=b.split(",");if(f.length>1){for(var g=0;g<f.length;g++)this.add(f[g],!0);return c||d.pushVal(),void 0}}var h=d.options.itemValue(b),i=d.options.itemText(b),j=d.options.tagClass(b),k=a.grep(d.itemsArray,function(a){return d.options.itemValue(a)===h})[0];if(k){if(d.options.onTagExists){var l=a(".tag",d.$container).filter(function(){return a(this).data("item")===k});d.options.onTagExists(b,l)}}else{d.itemsArray.push(b);var m=a('<span class="tag '+e(j)+'">'+e(i)+'<span data-role="remove"></span></span>');if(m.data("item",b),d.findInputWrapper().before(m),m.after(" "),d.isSelect&&!a('option[value="'+escape(h)+'"]',d.$element)[0]){var n=a("<option selected>"+e(i)+"</option>");n.data("item",b),n.attr("value",h),d.$element.append(n)}c||d.pushVal(),d.options.maxTags===d.itemsArray.length&&d.$container.addClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemAdded",{item:b}))}}}},remove:function(b,c){var d=this;d.objectItems&&(b="object"==typeof b?a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==d.options.itemValue(b)})[0]:a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==b})[0]),b&&(a(".tag",d.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",d.$element).filter(function(){return a(this).data("item")===b}).remove(),d.itemsArray.splice(a.inArray(b,d.itemsArray),1)),c||d.pushVal(),d.options.maxTags>d.itemsArray.length&&d.$container.removeClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemRemoved",{item:b}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(),b.options.maxTags&&!this.isEnabled()&&this.enable()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;e.options=a.extend({},g,b);var h=e.options.typeahead||{};e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),c(e.options,"tagClass"),e.options.source&&(h.source=e.options.source),h.source&&a.fn.typeahead&&(d(h,"source"),e.$input.typeahead({source:function(b,c){function d(a){for(var b=[],d=0;d<a.length;d++){var g=e.options.itemText(a[d]);f[g]=a[d],b.push(g)}c(b)}this.map={};var f=this.map,g=h.source(b);a.isFunction(g.success)?g.success(d):a.when(g).then(d)},updater:function(a){e.add(this.map[a])},matcher:function(a){return-1!==a.toLowerCase().indexOf(this.query.trim().toLowerCase())},sorter:function(a){return a.sort()},highlighter:function(a){var b=new RegExp("("+this.query+")","gi");return a.replace(b,"<strong>$1</strong>")}})),e.$container.on("click",a.proxy(function(){e.$input.focus()},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus());break;default:e.options.freeInput&&a.inArray(b.which,e.options.confirmKeys)>=0&&(e.add(c.val()),c.val(""),b.preventDefault())}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===g.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d){var e=[];return this.each(function(){var f=a(this).data("tagsinput");if(f){var g=f[c](d);void 0!==g&&e.push(g)}else f=new b(this,c),a(this).data("tagsinput",f),e.push(f),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?e.length>1?e:e[0]:e},a.fn.tagsinput.Constructor=b;var h=a("<div />");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
\ No newline at end of file
diff --git a/src/main/webapp/static/js/js.plugins.min.css b/src/main/webapp/static/js/js.plugins.min.css
index 47ef947ebd73f2bcac58dceacb52df9eca7320f6..06ff0c1c52cac791696633aafd4ea353e6142f26 100644
--- a/src/main/webapp/static/js/js.plugins.min.css
+++ b/src/main/webapp/static/js/js.plugins.min.css
@@ -1,4 +1,4 @@
-ul.tagit{padding:1px 5px;overflow:auto;margin-left:inherit;margin-right:inherit}ul.tagit li{display:block;float:left;margin:2px 5px 2px 0}ul.tagit li.tagit-choice{position:relative;line-height:inherit}ul.tagit li.tagit-choice-read-only{padding:.2em .5em .2em .5em}ul.tagit li.tagit-choice-editable{padding:.2em 18px .2em .5em}ul.tagit li.tagit-new{padding:.25em 4px .25em 0}ul.tagit li.tagit-choice a.tagit-label{cursor:pointer;text-decoration:none}ul.tagit li.tagit-choice .tagit-close{cursor:pointer;position:absolute;right:.1em;top:50%;margin-top:-8px;line-height:17px}ul.tagit li.tagit-choice .tagit-close .text-icon{display:none}ul.tagit li.tagit-choice input{display:block;float:left;margin:2px 5px 2px 0}ul.tagit input[type="text"]{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none;border:0;margin:0;padding:0;width:inherit;background-color:inherit;outline:0}body{font-family:Geneva,Arial,Helvetica,sans-serif;font-size:100%;*font-size:80%}.ui-layout-pane{background:#FFF;border:1px solid #BBB;padding:10px;overflow:auto}.ui-layout-content{padding:10px;position:relative;overflow:auto}.layout-child-container,.layout-content-container{padding:0;overflow:hidden}.layout-child-container{border:0}.layout-scroll{overflow:auto}.layout-hide{display:none}.ui-layout-resizer{background:#DDD;border:1px solid #BBB;border-width:0}.ui-layout-resizer-open-hover,.ui-layout-resizer-dragging{background:#c4e1a4}.ui-layout-resizer-dragging{border:1px solid #BBB}.ui-layout-resizer-north-dragging,.ui-layout-resizer-south-dragging{border-width:1px 0}.ui-layout-resizer-west-dragging,.ui-layout-resizer-east-dragging{border-width:0 1px}.ui-layout-resizer-dragging-limit{background:#e1a4a4}.ui-layout-resizer-closed-hover{background:#ebd5aa}.ui-layout-resizer-sliding{opacity:.10;filter:alpha(opacity=10)}.ui-layout-resizer-sliding-hover{opacity:1.00;filter:alpha(opacity=100)}.ui-layout-resizer-north-sliding-hover{border-bottom-width:1px}.ui-layout-resizer-south-sliding-hover{border-top-width:1px}.ui-layout-resizer-west-sliding-hover{border-right-width:1px}.ui-layout-resizer-east-sliding-hover{border-left-width:1px}.ui-layout-toggler{border:1px solid #BBB;background-color:#BBB}.ui-layout-resizer-hover .ui-layout-toggler{opacity:.60;filter:alpha(opacity=60)}.ui-layout-toggler-hover,.ui-layout-resizer-hover .ui-layout-toggler-hover{background-color:#FC6;opacity:1.00;filter:alpha(opacity=100)}.ui-layout-toggler-north,.ui-layout-toggler-south{border-width:0 1px}.ui-layout-toggler-west,.ui-layout-toggler-east{border-width:1px 0}.ui-layout-resizer-sliding .ui-layout-toggler{display:none}.ui-layout-toggler .content{color:#666;font-size:12px;font-weight:bold;width:100%;padding-bottom:.35ex}.ui-layout-mask{border:none!important;padding:0!important;margin:0!important;overflow:hidden!important;position:absolute!important;opacity:0!important;filter:Alpha(Opacity="0")!important}.ui-layout-mask-inside-pane{top:0!important;left:0!important;width:100%!important;height:100%!important}@media print{html{height:auto!important;overflow:visible!important}body.ui-layout-container{position:static!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;_width:auto!important;_height:auto!important}.ui-layout-resizer,.ui-layout-toggler{display:none!important}.ui-layout-pane{border:none!important;background:transparent!important;position:relative!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;width:auto!important;height:auto!important;overflow:visible!important}}/*!
+.bootstrap-tagsinput{background-color:#fff;border:1px solid #ccc;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);display:inline-block;padding:4px 6px;margin-bottom:10px;color:#555;vertical-align:middle;border-radius:4px;max-width:100%;line-height:22px}.bootstrap-tagsinput input{border:0;box-shadow:none;outline:0;background-color:transparent;padding:0;margin:0;width:auto!important;max-width:inherit}.bootstrap-tagsinput input:focus{border:0;box-shadow:none}.bootstrap-tagsinput .tag{margin-right:2px;color:white}.bootstrap-tagsinput .tag [data-role="remove"]{margin-left:8px;cursor:pointer}.bootstrap-tagsinput .tag [data-role="remove"]:after{content:"x";padding:0 2px}.bootstrap-tagsinput .tag [data-role="remove"]:hover{box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.bootstrap-tagsinput .tag [data-role="remove"]:hover:active{box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}body{font-family:Geneva,Arial,Helvetica,sans-serif;font-size:100%;*font-size:80%}.ui-layout-pane{background:#FFF;border:1px solid #BBB;padding:10px;overflow:auto}.ui-layout-content{padding:10px;position:relative;overflow:auto}.layout-child-container,.layout-content-container{padding:0;overflow:hidden}.layout-child-container{border:0}.layout-scroll{overflow:auto}.layout-hide{display:none}.ui-layout-resizer{background:#DDD;border:1px solid #BBB;border-width:0}.ui-layout-resizer-open-hover,.ui-layout-resizer-dragging{background:#c4e1a4}.ui-layout-resizer-dragging{border:1px solid #BBB}.ui-layout-resizer-north-dragging,.ui-layout-resizer-south-dragging{border-width:1px 0}.ui-layout-resizer-west-dragging,.ui-layout-resizer-east-dragging{border-width:0 1px}.ui-layout-resizer-dragging-limit{background:#e1a4a4}.ui-layout-resizer-closed-hover{background:#ebd5aa}.ui-layout-resizer-sliding{opacity:.10;filter:alpha(opacity=10)}.ui-layout-resizer-sliding-hover{opacity:1.00;filter:alpha(opacity=100)}.ui-layout-resizer-north-sliding-hover{border-bottom-width:1px}.ui-layout-resizer-south-sliding-hover{border-top-width:1px}.ui-layout-resizer-west-sliding-hover{border-right-width:1px}.ui-layout-resizer-east-sliding-hover{border-left-width:1px}.ui-layout-toggler{border:1px solid #BBB;background-color:#BBB}.ui-layout-resizer-hover .ui-layout-toggler{opacity:.60;filter:alpha(opacity=60)}.ui-layout-toggler-hover,.ui-layout-resizer-hover .ui-layout-toggler-hover{background-color:#FC6;opacity:1.00;filter:alpha(opacity=100)}.ui-layout-toggler-north,.ui-layout-toggler-south{border-width:0 1px}.ui-layout-toggler-west,.ui-layout-toggler-east{border-width:1px 0}.ui-layout-resizer-sliding .ui-layout-toggler{display:none}.ui-layout-toggler .content{color:#666;font-size:12px;font-weight:bold;width:100%;padding-bottom:.35ex}.ui-layout-mask{border:none!important;padding:0!important;margin:0!important;overflow:hidden!important;position:absolute!important;opacity:0!important;filter:Alpha(Opacity="0")!important}.ui-layout-mask-inside-pane{top:0!important;left:0!important;width:100%!important;height:100%!important}@media print{html{height:auto!important;overflow:visible!important}body.ui-layout-container{position:static!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;_width:auto!important;_height:auto!important}.ui-layout-resizer,.ui-layout-toggler{display:none!important}.ui-layout-pane{border:none!important;background:transparent!important;position:relative!important;top:auto!important;bottom:auto!important;left:auto!important;right:auto!important;width:auto!important;height:auto!important;overflow:visible!important}}/*!
  * FullCalendar v1.6.0 Stylesheet
  * Docs & License: http://arshaw.com/fullcalendar/
  * (c) 2013 Adam Shaw
diff --git a/src/main/webapp/static/themes/light/modules/_thirdparty.scss b/src/main/webapp/static/themes/light/modules/_thirdparty.scss
index 315eeae793380636948e0b4ad373608b255673db..c9b94e400e3a8ef13eb8830d4461b48cd4a5fca2 100644
--- a/src/main/webapp/static/themes/light/modules/_thirdparty.scss
+++ b/src/main/webapp/static/themes/light/modules/_thirdparty.scss
@@ -137,19 +137,6 @@
 	border: 1px solid $basecolor;
 }
 
-//overwrite tagit
-ul.tagit {
-	li.tagit-choice.ui-widget-content.ui-state-default {
-		background:#DEE7F8;
-		border: 1px solid #CAD8F3;
-	}
-}
-
-ul.tagit.ui-corner-all {
-	border:none;
-	background: none;
-}
-
 //overwrite uilayout
 .ui-layout-pane {
 	border:none;