From 1e853612bcd85143c777af05f061228a5f06de83 Mon Sep 17 00:00:00 2001 From: Steve Taylor Date: Tue, 23 Jul 2024 10:17:00 -0700 Subject: [PATCH] Replace bootstrap-tagsinput with Tom Select bootstrap-tagsinput is unsupported and out of date. Tom Select supports using a text input, has a similar method of loading remote data, and has both Bootstrap 4 and 5 assets. Vendoring the assets for now, but if we change the asset pipeline for Spotlight v4 perhaps we can remove that. --- .../javascripts/spotlight/spotlight.esm.js | 5879 +++++++++++++++-- .../spotlight/spotlight.esm.js.map | 2 +- app/assets/javascripts/spotlight/spotlight.js | 5879 +++++++++++++++-- .../javascripts/spotlight/spotlight.js.map | 2 +- .../stylesheets/spotlight/_catalog.scss | 15 - .../stylesheets/spotlight/_spotlight.scss | 1 + .../spotlight/_tom_select_fix.scss | 4 + .../admin/exhibit_tag_autocomplete.js | 67 +- app/javascript/spotlight/admin/index.js | 1 - .../spotlight/templates/spotlight.scss | 2 +- package-lock.json | 245 +- package.json | 11 +- rollup.config.js | 6 +- spec/features/bulk_actions_spec.rb | 6 +- .../lib/generators/test_app_generator.rb | 9 + .../assets/javascripts/bootstrap-tagsinput.js | 530 -- .../stylesheets/bootstrap-tagsinput.css | 46 - .../stylesheets/tom-select/_dropdown.scss | 99 + .../assets/stylesheets/tom-select/_items.scss | 112 + .../tom-select/plugins/checkbox_options.scss | 11 + .../tom-select/plugins/clear_button.scss | 33 + .../tom-select/plugins/drag_drop.scss | 10 + .../tom-select/plugins/dropdown_header.scss | 24 + .../tom-select/plugins/dropdown_input.scss | 43 + .../tom-select/plugins/input_autogrow.scss | 15 + .../tom-select/plugins/optgroup_columns.scss | 25 + .../tom-select/plugins/remove_button.scss | 70 + .../tom-select/tom-select.bootstrap4.min.css | 2 + .../tom-select/tom-select.bootstrap4.scss | 213 + .../tom-select/tom-select.bootstrap5.scss | 258 + .../tom-select/tom-select.default.scss | 89 + .../stylesheets/tom-select/tom-select.scss | 179 + 32 files changed, 12124 insertions(+), 1764 deletions(-) create mode 100644 app/assets/stylesheets/spotlight/_tom_select_fix.scss delete mode 100644 vendor/assets/javascripts/bootstrap-tagsinput.js delete mode 100644 vendor/assets/stylesheets/bootstrap-tagsinput.css create mode 100644 vendor/assets/stylesheets/tom-select/_dropdown.scss create mode 100644 vendor/assets/stylesheets/tom-select/_items.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/checkbox_options.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/clear_button.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/drag_drop.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/dropdown_header.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/dropdown_input.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/input_autogrow.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/optgroup_columns.scss create mode 100644 vendor/assets/stylesheets/tom-select/plugins/remove_button.scss create mode 100644 vendor/assets/stylesheets/tom-select/tom-select.bootstrap4.min.css create mode 100644 vendor/assets/stylesheets/tom-select/tom-select.bootstrap4.scss create mode 100644 vendor/assets/stylesheets/tom-select/tom-select.bootstrap5.scss create mode 100644 vendor/assets/stylesheets/tom-select/tom-select.default.scss create mode 100644 vendor/assets/stylesheets/tom-select/tom-select.scss diff --git a/app/assets/javascripts/spotlight/spotlight.esm.js b/app/assets/javascripts/spotlight/spotlight.esm.js index e8038f9c7..bd7e56ba6 100644 --- a/app/assets/javascripts/spotlight/spotlight.esm.js +++ b/app/assets/javascripts/spotlight/spotlight.esm.js @@ -905,535 +905,6 @@ Downcoder.Initialize = function() Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ; }; -/* From https://github.com/TimSchlechter/bootstrap-tagsinput/blob/2661784c2c281d3a69b93897ff3f39e4ffa5cbd1/dist/bootstrap-tagsinput.js */ - -/* The MIT License (MIT) - -Copyright (c) 2013 Tim Schlechter - -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. -*/ - -/* Retrieved 12 February 2014 */ - -(function ($) { - - var defaultOptions = { - tagClass: function(item) { - return 'badge badge-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 = $('
'); - this.$input = $('').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 = $('' + htmlEncode(itemText) + ''); - $tag.data('item', item); - self.findInputWrapper().before($tag); - $tag.after(' '); - - // add