diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html
index 77d83bf229c..94c4a5b7a6f 100644
--- a/solr/webapp/web/index.html
+++ b/solr/webapp/web/index.html
@@ -51,7 +51,7 @@ limitations under the License.
-
+
diff --git a/solr/webapp/web/libs/anfular-chosen.js b/solr/webapp/web/libs/anfular-chosen.js
new file mode 100644
index 00000000000..d73efd5b646
--- /dev/null
+++ b/solr/webapp/web/libs/anfular-chosen.js
@@ -0,0 +1,135 @@
+/*
+The MIT License
+Copyright (c) 2013 Localytics http://www.localytics.com
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+// Generated by CoffeeScript 1.8.0
+(function() {
+ var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+ angular.module('localytics.directives', []);
+
+ angular.module('localytics.directives').directive('chosen', [
+ '$timeout', function($timeout) {
+ var CHOSEN_OPTION_WHITELIST, NG_OPTIONS_REGEXP, isEmpty, snakeCase;
+ NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/;
+ CHOSEN_OPTION_WHITELIST = ['noResultsText', 'allowSingleDeselect', 'disableSearchThreshold', 'disableSearch', 'enableSplitWordSearch', 'inheritSelectClasses', 'maxSelectedOptions', 'placeholderTextMultiple', 'placeholderTextSingle', 'searchContains', 'singleBackstrokeDelete', 'displayDisabledOptions', 'displaySelectedOptions', 'width'];
+ snakeCase = function(input) {
+ return input.replace(/[A-Z]/g, function($1) {
+ return "_" + ($1.toLowerCase());
+ });
+ };
+ isEmpty = function(value) {
+ var key;
+ if (angular.isArray(value)) {
+ return value.length === 0;
+ } else if (angular.isObject(value)) {
+ for (key in value) {
+ if (value.hasOwnProperty(key)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ terminal: true,
+ link: function(scope, element, attr, ngModel) {
+ var chosen, defaultText, disableWithMessage, empty, initOrUpdate, match, options, origRender, removeEmptyMessage, startLoading, stopLoading, valuesExpr, viewWatch;
+ element.addClass('localytics-chosen');
+ options = scope.$eval(attr.chosen) || {};
+ angular.forEach(attr, function(value, key) {
+ if (__indexOf.call(CHOSEN_OPTION_WHITELIST, key) >= 0) {
+ return options[snakeCase(key)] = scope.$eval(value);
+ }
+ });
+ startLoading = function() {
+ return element.addClass('loading').attr('disabled', true).trigger('chosen:updated');
+ };
+ stopLoading = function() {
+ return element.removeClass('loading').attr('disabled', false).trigger('chosen:updated');
+ };
+ chosen = null;
+ defaultText = null;
+ empty = false;
+ initOrUpdate = function() {
+ if (chosen) {
+ return element.trigger('chosen:updated');
+ } else {
+ chosen = element.chosen(options).data('chosen');
+ return defaultText = chosen.default_text;
+ }
+ };
+ removeEmptyMessage = function() {
+ empty = false;
+ return element.attr('data-placeholder', defaultText);
+ };
+ disableWithMessage = function() {
+ empty = true;
+ return element.attr('data-placeholder', chosen.results_none_found).attr('disabled', true).trigger('chosen:updated');
+ };
+ if (ngModel) {
+ origRender = ngModel.$render;
+ ngModel.$render = function() {
+ origRender();
+ return initOrUpdate();
+ };
+ if (attr.multiple) {
+ viewWatch = function() {
+ return ngModel.$viewValue;
+ };
+ scope.$watch(viewWatch, ngModel.$render, true);
+ }
+ } else {
+ initOrUpdate();
+ }
+ attr.$observe('disabled', function() {
+ return element.trigger('chosen:updated');
+ });
+ if (attr.ngOptions && ngModel) {
+ match = attr.ngOptions.match(NG_OPTIONS_REGEXP);
+ valuesExpr = match[7];
+ scope.$watchCollection(valuesExpr, function(newVal, oldVal) {
+ var timer;
+ return timer = $timeout(function() {
+ if (angular.isUndefined(newVal)) {
+ return startLoading();
+ } else {
+ if (empty) {
+ removeEmptyMessage();
+ }
+ stopLoading();
+ if (isEmpty(newVal)) {
+ return disableWithMessage();
+ }
+ }
+ });
+ });
+ return scope.$on('$destroy', function(event) {
+ if (typeof timer !== "undefined" && timer !== null) {
+ return $timeout.cancel(timer);
+ }
+ });
+ }
+ }
+ };
+ }
+ ]);
+
+ }).call(this);
\ No newline at end of file