diff --git a/data/web/css/build/003-bootstrap-select.css b/data/web/css/build/003-bootstrap-select.css index f07f8fc2..e248901c 100644 --- a/data/web/css/build/003-bootstrap-select.css +++ b/data/web/css/build/003-bootstrap-select.css @@ -1,10 +1,10 @@ -/*! - * Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select) - * - * Copyright 2012-2020 SnapAppointments, LLC - * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) - */ - +/*! + * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select) + * + * Copyright 2012-2021 SnapAppointments, LLC + * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) + */ + @-webkit-keyframes bs-notify-fadeOut { 0% { opacity: 0.9; @@ -253,6 +253,27 @@ select.selectpicker { margin-top: -2px; vertical-align: middle; } +.bootstrap-select .dropdown-toggle .bs-select-clear-selected { + position: relative; + display: block; + margin-right: 5px; + text-align: center; +} +.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected { + padding-right: inherit; +} +.bootstrap-select .dropdown-toggle .bs-select-clear-selected span { + position: relative; + top: -webkit-calc(((-1em / 1.5) + 1ex) / 2); + top: calc(((-1em / 1.5) + 1ex) / 2); + pointer-events: none; +} +.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected span { + top: auto; +} +.bootstrap-select .dropdown-toggle.bs-placeholder .bs-select-clear-selected { + display: none; +} .input-group .bootstrap-select.form-control .dropdown-toggle { border-radius: inherit; } @@ -368,6 +389,8 @@ select.selectpicker { height: 1em; border-style: solid; border-width: 0 0.26em 0.26em 0; + -webkit-transform-style: preserve-3d; + transform-style: preserve-3d; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); -o-transform: rotate(45deg); @@ -434,6 +457,9 @@ select.selectpicker { -moz-box-sizing: border-box; box-sizing: border-box; } +.bs-actionsbox .btn-group { + display: block; +} .bs-actionsbox .btn-group button { width: 50%; } @@ -444,6 +470,9 @@ select.selectpicker { -moz-box-sizing: border-box; box-sizing: border-box; } +.bs-donebutton .btn-group { + display: block; +} .bs-donebutton .btn-group button { width: 100%; } diff --git a/data/web/js/build/004-bootstrap-select.js b/data/web/js/build/004-bootstrap-select.js index b76b97d9..fe063b2e 100644 --- a/data/web/js/build/004-bootstrap-select.js +++ b/data/web/js/build/004-bootstrap-select.js @@ -1,7 +1,7 @@ /*! - * Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select) + * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select) * - * Copyright 2012-2020 SnapAppointments, LLC + * Copyright 2012-2021 SnapAppointments, LLC * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) */ @@ -88,6 +88,8 @@ */ var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i; + var ParseableAttributes = ['title', 'placeholder']; // attributes to use as settings, can add others in the future + function allowedAttribute (attr, allowedAttributeList) { var attrName = attr.nodeName.toLowerCase() @@ -147,6 +149,24 @@ } } + function getAttributesObject ($select) { + var attributesObject = {}, + attrVal; + + ParseableAttributes.forEach(function (item) { + attrVal = $select.attr(item); + if (attrVal) attributesObject[item] = attrVal; + }); + + // for backwards compatibility + // (using title as placeholder is deprecated - remove in v2.0.0) + if (!attributesObject.placeholder && attributesObject.title) { + attributesObject.placeholder = attributesObject.title; + } + + return attributesObject; + } + // Polyfill for browsers with no classList support // Remove in v2 if (!('classList' in document.createElement('_'))) { @@ -246,16 +266,6 @@ if (!String.prototype.startsWith) { (function () { 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` - var defineProperty = (function () { - // IE 8 only supports `Object.defineProperty` on DOM elements - try { - var object = {}; - var $defineProperty = Object.defineProperty; - var result = $defineProperty(object, object, object) && $defineProperty; - } catch (error) { - } - return result; - }()); var toString = {}.toString; var startsWith = function (search) { if (this == null) { @@ -287,8 +297,8 @@ } return true; }; - if (defineProperty) { - defineProperty(String.prototype, 'startsWith', { + if (Object.defineProperty) { + Object.defineProperty(String.prototype, 'startsWith', { 'value': startsWith, 'configurable': true, 'writable': true @@ -299,67 +309,43 @@ }()); } - if (!Object.keys) { - Object.keys = function ( - o, // object - k, // key - r // result array - ) { - // initialize object and result - r = []; - // iterate over object keys - for (k in o) { - // fill result array with non-prototypical keys - r.hasOwnProperty.call(o, k) && r.push(k); - } - // return result - return r; - }; - } - - if (HTMLSelectElement && !HTMLSelectElement.prototype.hasOwnProperty('selectedOptions')) { - Object.defineProperty(HTMLSelectElement.prototype, 'selectedOptions', { - get: function () { - return this.querySelectorAll(':checked'); - } - }); - } - - function getSelectedOptions (select, ignoreDisabled) { - var selectedOptions = select.selectedOptions, - options = [], - opt; - - if (ignoreDisabled) { - for (var i = 0, len = selectedOptions.length; i < len; i++) { - opt = selectedOptions[i]; - - if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) { - options.push(opt); - } + function getSelectedOptions () { + var selectedOptions = this.selectpicker.main.data.filter(function (item) { + if (item.selected) { + if (this.options.hideDisabled && item.disabled) return false; + return true; } - return options; + return false; + }, this); + + // ensure only 1 option is selected if multiple are set in the data source + if (this.options.source.data && !this.multiple && selectedOptions.length > 1) { + for (var i = 0; i < selectedOptions.length - 1; i++) { + selectedOptions[i].selected = false; + } + + selectedOptions = [ selectedOptions[selectedOptions.length - 1] ]; } return selectedOptions; } // much faster than $.val() - function getSelectValues (select, selectedOptions) { + function getSelectValues (selectedOptions) { var value = [], - options = selectedOptions || select.selectedOptions, + options = selectedOptions || getSelectedOptions.call(this), opt; for (var i = 0, len = options.length; i < len; i++) { opt = options[i]; - if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) { - value.push(opt.value); + if (!opt.disabled) { + value.push(opt.value === undefined ? opt.text : opt.value); } } - if (!select.multiple) { + if (!this.multiple) { return !value.length ? null : value[0]; } @@ -408,13 +394,6 @@ } el.dispatchEvent(event); - } else if (el.fireEvent) { // for IE8 - event = document.createEventObject(); - event.eventType = eventName; - el.fireEvent('on' + eventName, event); - } else { - // fall back to jQuery.trigger - this.trigger(eventName); } }; // @@ -442,7 +421,9 @@ if (normalize) string = normalizeToBase(string); string = string.toUpperCase(); - if (method === 'contains') { + if (typeof method === 'function') { + searchSuccess = method(string, searchString); + } else if (method === 'contains') { searchSuccess = string.indexOf(searchString) >= 0; } else { searchSuccess = string.startsWith(searchString); @@ -640,13 +621,28 @@ ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key } + // eslint-disable-next-line no-undef + var Dropdown = window.Dropdown || bootstrap.Dropdown; + + function getVersion () { + var version; + + try { + version = $.fn.dropdown.Constructor.VERSION; + } catch (err) { + version = Dropdown.VERSION; + } + + return version; + } + var version = { success: false, major: '3' }; try { - version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.'); + version.full = (getVersion() || '').split(' ')[0].split('.'); version.major = version.full[0]; version.success = true; } catch (err) { @@ -673,21 +669,30 @@ } var Selector = { - MENU: '.' + classNames.MENU + MENU: '.' + classNames.MENU, + DATA_TOGGLE: 'data-toggle="dropdown"' } var elementTemplates = { + div: document.createElement('div'), span: document.createElement('span'), i: document.createElement('i'), subtext: document.createElement('small'), a: document.createElement('a'), li: document.createElement('li'), whitespace: document.createTextNode('\u00A0'), - fragment: document.createDocumentFragment() + fragment: document.createDocumentFragment(), + option: document.createElement('option') } + elementTemplates.selectedOption = elementTemplates.option.cloneNode(false); + elementTemplates.selectedOption.setAttribute('selected', true); + + elementTemplates.noResults = elementTemplates.li.cloneNode(false); + elementTemplates.noResults.className = 'no-results'; + elementTemplates.a.setAttribute('role', 'option'); - if (version.major === '4') elementTemplates.a.className = 'dropdown-item'; + elementTemplates.a.className = 'dropdown-item'; elementTemplates.subtext.className = 'text-muted'; @@ -728,7 +733,7 @@ } } - if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(' ')); + if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(/\s+/)); if (inline) a.setAttribute('style', inline); return a; @@ -803,6 +808,71 @@ } } + var getOptionData = { + fromOption: function (option, type) { + var value; + + switch (type) { + case 'divider': + value = option.getAttribute('data-divider') === 'true'; + break; + + case 'text': + value = option.textContent; + break; + + case 'label': + value = option.label; + break; + + case 'style': + value = option.style.cssText; + break; + + case 'content': + case 'tokens': + case 'subtext': + case 'icon': + value = option.getAttribute('data-' + type); + break; + } + + return value; + }, + fromDataSource: function (option, type) { + var value; + + switch (type) { + case 'text': + case 'label': + value = option.text || option.value || ''; + break; + + case 'divider': + case 'style': + case 'content': + case 'tokens': + case 'subtext': + case 'icon': + value = option[type]; + break; + } + + return value; + } + } + + function showNoResults (searchMatch, searchValue) { + if (!searchMatch.length) { + elementTemplates.noResults.innerHTML = this.options.noneResultsText.replace('{0}', '"' + htmlEscape(searchValue) + '"'); + this.$menuInner[0].firstChild.appendChild(elementTemplates.noResults); + } + } + + function filterHidden (item) { + return !(item.hidden || this.options.hideDisabled && item.disabled); + } + var Selectpicker = function (element, options) { var that = this; @@ -818,7 +888,9 @@ this.$menu = null; this.options = options; this.selectpicker = { - main: {}, + main: { + optionQueue: elementTemplates.fragment.cloneNode(false) + }, search: {}, current: {}, // current changes if a search is in progress view: {}, @@ -837,12 +909,6 @@ this.sizeInfo = {}; - // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a - // data-attribute) - if (this.options.title === null) { - this.options.title = this.$element.attr('title'); - } - // Format window padding var winPad = this.options.windowPadding; if (typeof winPad === 'number') { @@ -864,7 +930,7 @@ this.init(); }; - Selectpicker.VERSION = '1.13.14'; + Selectpicker.VERSION = '1.14.0-beta2'; // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both. Selectpicker.DEFAULTS = { @@ -881,6 +947,8 @@ }, selectAllText: 'Select All', deselectAllText: 'Deselect All', + source: {}, + chunkSize: 40, doneButton: false, doneButtonText: 'Close', multipleSeparator: ', ', @@ -888,6 +956,8 @@ style: classNames.BUTTONCLASS, size: 'auto', title: null, + placeholder: null, + allowClear: false, selectedTextFormat: 'values', width: false, container: false, @@ -926,32 +996,59 @@ init: function () { var that = this, - id = this.$element.attr('id'); + id = this.$element.attr('id'), + element = this.$element[0], + form = element.form; selectId++; this.selectId = 'bs-select-' + selectId; - this.$element[0].classList.add('bs-select-hidden'); + element.classList.add('bs-select-hidden'); this.multiple = this.$element.prop('multiple'); this.autofocus = this.$element.prop('autofocus'); - if (this.$element[0].classList.contains('show-tick')) { + if (element.classList.contains('show-tick')) { this.options.showTick = true; } this.$newElement = this.createDropdown(); - this.buildData(); + this.$element .after(this.$newElement) .prependTo(this.$newElement); + // ensure select is associated with form element if it got unlinked after moving it inside newElement + if (form && element.form === null) { + if (!form.id) form.id = 'form-' + this.selectId; + element.setAttribute('form', form.id); + } + this.$button = this.$newElement.children('button'); + if (this.options.allowClear) this.$clearButton = this.$button.children('.bs-select-clear-selected'); this.$menu = this.$newElement.children(Selector.MENU); this.$menuInner = this.$menu.children('.inner'); this.$searchbox = this.$menu.find('input'); - this.$element[0].classList.remove('bs-select-hidden'); + element.classList.remove('bs-select-hidden'); + + this.fetchData(function () { + that.render(true); + that.buildList(); + + requestAnimationFrame(function () { + that.$element.trigger('loaded' + EVENT_KEY); + }); + }); + + this.fetchData(function () { + that.render(true); + that.buildList(); + + requestAnimationFrame(function () { + that.$element.trigger('loaded' + EVENT_KEY); + }); + }); if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT); @@ -962,6 +1059,8 @@ this.checkDisabled(); this.clickListener(); + if (version.major > 4) this.dropdown = new Dropdown(this.$button[0]); + if (this.options.liveSearch) { this.liveSearchListener(); this.focusedParent = this.$searchbox[0]; @@ -970,7 +1069,6 @@ } this.setStyle(); - this.render(); this.setWidth(); if (this.options.container) { this.selectPosition(); @@ -1006,7 +1104,7 @@ } }); - if (that.$element[0].hasAttribute('required')) { + if (element.hasAttribute('required')) { this.$element.on('invalid' + EVENT_KEY, function () { that.$button[0].classList.add('bs-invalid'); @@ -1029,10 +1127,13 @@ }); } - setTimeout(function () { - that.buildList(); - that.$element.trigger('loaded' + EVENT_KEY); - }); + if (form) { + $(form).on('reset' + EVENT_KEY, function () { + requestAnimationFrame(function () { + that.render(); + }); + }); + } }, createDropdown: function () { @@ -1052,7 +1153,8 @@ header = '', searchbox = '', actionsbox = '', - donebutton = ''; + donebutton = '', + clearButton = ''; if (this.options.header) { header = @@ -1078,7 +1180,7 @@ if (this.multiple && this.options.actionsBox) { actionsbox = '