bootstrap4-select-rails 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +46 -0
  6. data/README.md +40 -0
  7. data/Rakefile +32 -0
  8. data/bootstrap4-select-rails.gemspec +23 -0
  9. data/lib/bootstrap4-select-rails.rb +14 -0
  10. data/lib/bootstrap4-select-rails/engine.rb +8 -0
  11. data/lib/bootstrap4-select-rails/railtie.rb +7 -0
  12. data/lib/bootstrap4-select-rails/version.rb +7 -0
  13. data/vendor/assets/javascripts/.jshintrc +15 -0
  14. data/vendor/assets/javascripts/bootstrap-select.js +1860 -0
  15. data/vendor/assets/javascripts/bootstrap-select.min.js +7 -0
  16. data/vendor/assets/javascripts/i18n/defaults-ar_AR.js +49 -0
  17. data/vendor/assets/javascripts/i18n/defaults-ar_AR.min.js +12 -0
  18. data/vendor/assets/javascripts/i18n/defaults-bg_BG.js +44 -0
  19. data/vendor/assets/javascripts/i18n/defaults-bg_BG.min.js +7 -0
  20. data/vendor/assets/javascripts/i18n/defaults-cro_CRO.js +44 -0
  21. data/vendor/assets/javascripts/i18n/defaults-cro_CRO.min.js +7 -0
  22. data/vendor/assets/javascripts/i18n/defaults-cs_CZ.js +35 -0
  23. data/vendor/assets/javascripts/i18n/defaults-cs_CZ.min.js +7 -0
  24. data/vendor/assets/javascripts/i18n/defaults-da_DK.js +44 -0
  25. data/vendor/assets/javascripts/i18n/defaults-da_DK.min.js +7 -0
  26. data/vendor/assets/javascripts/i18n/defaults-de_DE.js +44 -0
  27. data/vendor/assets/javascripts/i18n/defaults-de_DE.min.js +7 -0
  28. data/vendor/assets/javascripts/i18n/defaults-en_US.js +44 -0
  29. data/vendor/assets/javascripts/i18n/defaults-en_US.min.js +7 -0
  30. data/vendor/assets/javascripts/i18n/defaults-es_CL.js +37 -0
  31. data/vendor/assets/javascripts/i18n/defaults-es_CL.min.js +7 -0
  32. data/vendor/assets/javascripts/i18n/defaults-es_ES.js +37 -0
  33. data/vendor/assets/javascripts/i18n/defaults-es_ES.min.js +7 -0
  34. data/vendor/assets/javascripts/i18n/defaults-et_EE.js +23 -0
  35. data/vendor/assets/javascripts/i18n/defaults-eu.js +35 -0
  36. data/vendor/assets/javascripts/i18n/defaults-eu.min.js +7 -0
  37. data/vendor/assets/javascripts/i18n/defaults-fa_IR.js +37 -0
  38. data/vendor/assets/javascripts/i18n/defaults-fa_IR.min.js +7 -0
  39. data/vendor/assets/javascripts/i18n/defaults-fi_FI.js +44 -0
  40. data/vendor/assets/javascripts/i18n/defaults-fi_FI.min.js +7 -0
  41. data/vendor/assets/javascripts/i18n/defaults-fr_FR.js +44 -0
  42. data/vendor/assets/javascripts/i18n/defaults-fr_FR.min.js +7 -0
  43. data/vendor/assets/javascripts/i18n/defaults-hu_HU.js +44 -0
  44. data/vendor/assets/javascripts/i18n/defaults-hu_HU.min.js +7 -0
  45. data/vendor/assets/javascripts/i18n/defaults-id_ID.js +37 -0
  46. data/vendor/assets/javascripts/i18n/defaults-id_ID.min.js +7 -0
  47. data/vendor/assets/javascripts/i18n/defaults-it_IT.js +39 -0
  48. data/vendor/assets/javascripts/i18n/defaults-it_IT.min.js +7 -0
  49. data/vendor/assets/javascripts/i18n/defaults-ko_KR.js +44 -0
  50. data/vendor/assets/javascripts/i18n/defaults-ko_KR.min.js +7 -0
  51. data/vendor/assets/javascripts/i18n/defaults-lt_LT.js +44 -0
  52. data/vendor/assets/javascripts/i18n/defaults-lt_LT.min.js +7 -0
  53. data/vendor/assets/javascripts/i18n/defaults-nb_NO.js +44 -0
  54. data/vendor/assets/javascripts/i18n/defaults-nb_NO.min.js +7 -0
  55. data/vendor/assets/javascripts/i18n/defaults-nl_NL.js +37 -0
  56. data/vendor/assets/javascripts/i18n/defaults-nl_NL.min.js +7 -0
  57. data/vendor/assets/javascripts/i18n/defaults-pl_PL.js +37 -0
  58. data/vendor/assets/javascripts/i18n/defaults-pl_PL.min.js +7 -0
  59. data/vendor/assets/javascripts/i18n/defaults-pt_BR.js +35 -0
  60. data/vendor/assets/javascripts/i18n/defaults-pt_BR.min.js +7 -0
  61. data/vendor/assets/javascripts/i18n/defaults-pt_PT.js +35 -0
  62. data/vendor/assets/javascripts/i18n/defaults-pt_PT.min.js +7 -0
  63. data/vendor/assets/javascripts/i18n/defaults-ro_RO.js +35 -0
  64. data/vendor/assets/javascripts/i18n/defaults-ro_RO.min.js +7 -0
  65. data/vendor/assets/javascripts/i18n/defaults-ru_RU.js +38 -0
  66. data/vendor/assets/javascripts/i18n/defaults-ru_RU.min.js +7 -0
  67. data/vendor/assets/javascripts/i18n/defaults-sk_SK.js +37 -0
  68. data/vendor/assets/javascripts/i18n/defaults-sk_SK.min.js +7 -0
  69. data/vendor/assets/javascripts/i18n/defaults-sl_SI.js +44 -0
  70. data/vendor/assets/javascripts/i18n/defaults-sl_SI.min.js +7 -0
  71. data/vendor/assets/javascripts/i18n/defaults-sv_SE.js +44 -0
  72. data/vendor/assets/javascripts/i18n/defaults-sv_SE.min.js +7 -0
  73. data/vendor/assets/javascripts/i18n/defaults-tr_TR.js +44 -0
  74. data/vendor/assets/javascripts/i18n/defaults-tr_TR.min.js +7 -0
  75. data/vendor/assets/javascripts/i18n/defaults-ua_UA.js +35 -0
  76. data/vendor/assets/javascripts/i18n/defaults-ua_UA.min.js +7 -0
  77. data/vendor/assets/javascripts/i18n/defaults-zh_CN.js +35 -0
  78. data/vendor/assets/javascripts/i18n/defaults-zh_CN.min.js +7 -0
  79. data/vendor/assets/javascripts/i18n/defaults-zh_TW.js +37 -0
  80. data/vendor/assets/javascripts/i18n/defaults-zh_TW.min.js +7 -0
  81. data/vendor/assets/stylesheets/bootstrap-select.css.map +7 -0
  82. data/vendor/assets/stylesheets/bootstrap-select.scss +421 -0
  83. data/vendor/assets/stylesheets/variables.scss +9 -0
  84. data/version.txt +1 -0
  85. metadata +155 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: acaf59b536fa5b1fe735beeacdc1d8f74c6b0a47
4
+ data.tar.gz: b235019c7d07c37f45fdbaf1429c2f5593e87854
5
+ SHA512:
6
+ metadata.gz: fc996211a05d377b819921de30c288dc2bc1feaf08762870972ce98c4274dffc7e2bded755317de3a5b6e32f8b0bda2825ac64904f893ca5c6f581d0bc72e032
7
+ data.tar.gz: 81f21ae3d5e54ea78cfabb217073d6bc7aa87370210de4581214e8a9ef9b36e661b6da91ffbbb6054be3c709c6c52faa0c13ff55a6700d581408b7d9ec456729
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,9 @@
1
+ # Change Log
2
+
3
+ ## [v1.3.0.1](https://github.com/karagenit/bootstrap-select-rails/tree/v1.3.0.1) (2013-05-24)
4
+ [Full Changelog](https://github.com/karagenit/bootstrap-select-rails/compare/v1.3.0...v1.3.0.1)
5
+
6
+ ## [v1.3.0](https://github.com/karagenit/bootstrap-select-rails/tree/v1.3.0) (2013-05-24)
7
+
8
+
9
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bootstrap-select-rails.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,46 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Caleb Smith
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ -------------------------ORIGINAL LICENSE--------------------------------
24
+
25
+ Copyright (c) 2013 Maciej Krajowski-Kukiel
26
+
27
+ MIT License
28
+
29
+ Permission is hereby granted, free of charge, to any person obtaining
30
+ a copy of this software and associated documentation files (the
31
+ "Software"), to deal in the Software without restriction, including
32
+ without limitation the rights to use, copy, modify, merge, publish,
33
+ distribute, sublicense, and/or sell copies of the Software, and to
34
+ permit persons to whom the Software is furnished to do so, subject to
35
+ the following conditions:
36
+
37
+ The above copyright notice and this permission notice shall be
38
+ included in all copies or substantial portions of the Software.
39
+
40
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
41
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
42
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
43
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
44
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
45
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
46
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,40 @@
1
+ # Bootstrap::Select::Rails
2
+
3
+ `bootstrap-select`, fixed for Bootstrap 4 (Alpha 6) and packaged into a Gem for Rails.
4
+
5
+ This is a fork of the original [bootstrap-select-rails](https://github.com/Slashek/bootstrap-select-rails) Gem repository. The original is based on [bootstrap-select](https://github.com/silviomoreto/bootstrap-select), but as this library isn't compatible with Bootstrap 4, I rewrote the Gem to use [a fork of the original](https://github.com/heimrichhannot/bootstrap-select) that is compatible.
6
+
7
+ ## Preprequisites
8
+
9
+ You will need to install Bootstrap 4 & jQuery 3, through the `bootstrap` and `jquery-rails` gems (respectively).
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'bootstrap4-select-rails'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install bootstrap4-select-rails
24
+
25
+ ## Usage
26
+
27
+ In your `app/assets/stylesheets/application.scss`, add the following:
28
+
29
+ @import "bootstrap-select";
30
+
31
+ If you intend to use features such as the live search, you must add the following to `app/assets/javascripts/application.js`:
32
+
33
+ //= require bootstrap-select
34
+
35
+ Also, you must require at least the *alert* and *dropdown* bootstrap components. For example, if you're using [bootstrap-sass](https://github.com/twbs/bootstrap-sass):
36
+
37
+ //= require bootstrap/alert
38
+ //= require bootstrap/dropdown
39
+
40
+ Otherwise, requiring all of `bootstrap` or `bootstrap-sprockets` will work.
@@ -0,0 +1,32 @@
1
+ task :default => [:clean, :build, :install]
2
+
3
+ task :build do
4
+ sh "bundle install"
5
+ sh "gem build bootstrap4-select-rails.gemspec"
6
+ sh "rdoc lib/"
7
+ end
8
+
9
+ task :install do
10
+ sh "gem install bootstrap4-select-rails-" + IO.read('version.txt') + ".gem"
11
+ end
12
+
13
+ task :clean do
14
+ sh "gem uninstall bootstrap4-select-rails"
15
+ sh "rm *.gem"
16
+ end
17
+
18
+ task :publish do
19
+ puts "Current Version: " + IO.read('version.txt')
20
+ print "New Version: "
21
+ vers = STDIN.gets.chomp
22
+ IO.write('version.txt', vers)
23
+ sh "rake build"
24
+ sh "git commit -am \"Update Version\""
25
+ sh "git tag -a v" + vers + " -m \"\""
26
+ sh "git push origin master"
27
+ sh "git push origin v" + IO.read('version.txt')
28
+ sh "github_changelog_generator"
29
+ sh "git commit -am \"Update Changelog\""
30
+ sh "git push origin master"
31
+ sh "gem push bootstrap4-select-rails-" + IO.read('version.txt') + ".gem"
32
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bootstrap4-select-rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bootstrap4-select-rails"
8
+ spec.version = Bootstrap4::Select::Rails::VERSION
9
+ spec.authors = ["Caleb Smith"]
10
+ spec.email = ["karagenit@outlook.com"]
11
+ spec.description = "bootstrap-select Gem for Rails"
12
+ spec.summary = "Updated version of bootstrap-select, compatible with Bootstrap 4 (Alpha 6)"
13
+ spec.homepage = "https://github.com/karagenit/bootstrap-select-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake", "~> 12.2"
23
+ end
@@ -0,0 +1,14 @@
1
+ require "rails"
2
+ require "bootstrap4-select-rails/version"
3
+
4
+ module Bootstrap4
5
+ module Select
6
+ module Rails
7
+ if ::Rails.version < "3.1"
8
+ require "bootstrap4-select-rails/railtie"
9
+ else
10
+ require "bootstrap4-select-rails/engine"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ module Bootstrap4
2
+ module Select
3
+ module Rails
4
+ class Engine < ::Rails::Engine
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Bootstrap4
2
+ module Select
3
+ module Rails
4
+ class Railtie < ::Rails::Railtie; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Bootstrap4
2
+ module Select
3
+ module Rails
4
+ VERSION = "2.0.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ {
2
+ "curly": true,
3
+ "eqeqeq": true,
4
+ "immed": true,
5
+ "latedef": true,
6
+ "newcap": true,
7
+ "noarg": true,
8
+ "sub": true,
9
+ "undef": true,
10
+ "unused": true,
11
+ "boss": true,
12
+ "eqnull": true,
13
+ "browser": true,
14
+ "jquery": true
15
+ }
@@ -0,0 +1,1860 @@
1
+ /*!
2
+ * Bootstrap-select v1.12.13 (https://github.com/heimrichhannot/bootstrap-select)
3
+ *
4
+ * Copyright 2013-2017 bootstrap-select
5
+ * Licensed under MIT (https://github.com/heimrichhannot/bootstrap-select/LICENSE)
6
+ */
7
+
8
+ (function(root, factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ // AMD. Register as an anonymous module unless amdModuleId is set
11
+ define(['jquery'], function(a0) {
12
+ return (factory(a0));
13
+ });
14
+ } else if (typeof module === 'object' && module.exports) {
15
+ // Node. Does not work with strict CommonJS, but
16
+ // only CommonJS-like environments that support module.exports,
17
+ // like Node.
18
+ module.exports = factory(require('jquery'));
19
+ } else {
20
+ factory(root['jQuery']);
21
+ }
22
+ }(this, function(jQuery) {
23
+
24
+ (function($) {
25
+ 'use strict';
26
+
27
+ //<editor-fold desc="Shims">
28
+ if (!String.prototype.includes) {
29
+ (function() {
30
+ 'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
31
+ var toString = {}.toString;
32
+ var defineProperty = (function() {
33
+ // IE 8 only supports `Object.defineProperty` on DOM elements
34
+ try {
35
+ var object = {};
36
+ var $defineProperty = Object.defineProperty;
37
+ var result = $defineProperty(object, object, object) && $defineProperty;
38
+ } catch (error) {
39
+ }
40
+ return result;
41
+ }());
42
+ var indexOf = ''.indexOf;
43
+ var includes = function(search) {
44
+ if (this == null) {
45
+ throw new TypeError();
46
+ }
47
+ var string = String(this);
48
+ if (search && toString.call(search) == '[object RegExp]') {
49
+ throw new TypeError();
50
+ }
51
+ var stringLength = string.length;
52
+ var searchString = String(search);
53
+ var searchLength = searchString.length;
54
+ var position = arguments.length > 1 ? arguments[1] : undefined;
55
+ // `ToInteger`
56
+ var pos = position ? Number(position) : 0;
57
+ if (pos != pos) { // better `isNaN`
58
+ pos = 0;
59
+ }
60
+ var start = Math.min(Math.max(pos, 0), stringLength);
61
+ // Avoid the `indexOf` call if no match is possible
62
+ if (searchLength + start > stringLength) {
63
+ return false;
64
+ }
65
+ return indexOf.call(string, searchString, pos) != -1;
66
+ };
67
+ if (defineProperty) {
68
+ defineProperty(String.prototype, 'includes', {
69
+ 'value': includes,
70
+ 'configurable': true,
71
+ 'writable': true,
72
+ });
73
+ } else {
74
+ String.prototype.includes = includes;
75
+ }
76
+ }());
77
+ }
78
+
79
+ if (!String.prototype.startsWith) {
80
+ (function() {
81
+ 'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
82
+ var defineProperty = (function() {
83
+ // IE 8 only supports `Object.defineProperty` on DOM elements
84
+ try {
85
+ var object = {};
86
+ var $defineProperty = Object.defineProperty;
87
+ var result = $defineProperty(object, object, object) && $defineProperty;
88
+ } catch (error) {
89
+ }
90
+ return result;
91
+ }());
92
+ var toString = {}.toString;
93
+ var startsWith = function(search) {
94
+ if (this == null) {
95
+ throw new TypeError();
96
+ }
97
+ var string = String(this);
98
+ if (search && toString.call(search) == '[object RegExp]') {
99
+ throw new TypeError();
100
+ }
101
+ var stringLength = string.length;
102
+ var searchString = String(search);
103
+ var searchLength = searchString.length;
104
+ var position = arguments.length > 1 ? arguments[1] : undefined;
105
+ // `ToInteger`
106
+ var pos = position ? Number(position) : 0;
107
+ if (pos != pos) { // better `isNaN`
108
+ pos = 0;
109
+ }
110
+ var start = Math.min(Math.max(pos, 0), stringLength);
111
+ // Avoid the `indexOf` call if no match is possible
112
+ if (searchLength + start > stringLength) {
113
+ return false;
114
+ }
115
+ var index = -1;
116
+ while (++index < searchLength) {
117
+ if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ };
123
+ if (defineProperty) {
124
+ defineProperty(String.prototype, 'startsWith', {
125
+ 'value': startsWith,
126
+ 'configurable': true,
127
+ 'writable': true,
128
+ });
129
+ } else {
130
+ String.prototype.startsWith = startsWith;
131
+ }
132
+ }());
133
+ }
134
+
135
+ if (!Object.keys) {
136
+ Object.keys = function(
137
+ o, // object
138
+ k, // key
139
+ r // result array
140
+ ) {
141
+ // initialize object and result
142
+ r = [];
143
+ // iterate over object keys
144
+ for (k in o)
145
+ // fill result array with non-prototypical keys
146
+ r.hasOwnProperty.call(o, k) && r.push(k);
147
+ // return result
148
+ return r;
149
+ };
150
+ }
151
+
152
+ // set data-selected on select element if the value has been programmatically selected
153
+ // prior to initialization of bootstrap-select
154
+ // * consider removing or replacing an alternative method *
155
+ var valHooks = {
156
+ useDefault: false,
157
+ _set: $.valHooks.select.set,
158
+ };
159
+
160
+ $.valHooks.select.set = function(elem, value) {
161
+ if (value && !valHooks.useDefault) $(elem).data('selected', true);
162
+
163
+ return valHooks._set.apply(this, arguments);
164
+ };
165
+
166
+ var changed_arguments = null;
167
+ $.fn.triggerNative = function(eventName) {
168
+ var el = this[0],
169
+ event;
170
+
171
+ if (el.dispatchEvent) { // for modern browsers & IE9+
172
+ if (typeof Event === 'function') {
173
+ // For modern browsers
174
+ event = new Event(eventName, {
175
+ bubbles: true,
176
+ });
177
+ } else {
178
+ // For IE since it doesn't support Event constructor
179
+ event = document.createEvent('Event');
180
+ event.initEvent(eventName, true, false);
181
+ }
182
+
183
+ el.dispatchEvent(event);
184
+ } else if (el.fireEvent) { // for IE8
185
+ event = document.createEventObject();
186
+ event.eventType = eventName;
187
+ el.fireEvent('on' + eventName, event);
188
+ } else {
189
+ // fall back to jQuery.trigger
190
+ this.trigger(eventName);
191
+ }
192
+ };
193
+ //</editor-fold>
194
+
195
+ // Case insensitive contains search
196
+ $.expr.pseudos.icontains = function(obj, index, meta) {
197
+ var $obj = $(obj).find('span.dropdown-item-inner');
198
+ var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
199
+ return haystack.includes(meta[3].toUpperCase());
200
+ };
201
+
202
+ // Case insensitive begins search
203
+ $.expr.pseudos.ibegins = function(obj, index, meta) {
204
+ var $obj = $(obj).find('span.dropdown-item-inner');
205
+ var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
206
+ return haystack.startsWith(meta[3].toUpperCase());
207
+ };
208
+
209
+ // Case and accent insensitive contains search
210
+ $.expr.pseudos.aicontains = function(obj, index, meta) {
211
+ var $obj = $(obj).find('span.dropdown-item-inner');
212
+ var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
213
+ return haystack.includes(meta[3].toUpperCase());
214
+ };
215
+
216
+ // Case and accent insensitive begins search
217
+ $.expr.pseudos.aibegins = function(obj, index, meta) {
218
+ var $obj = $(obj).find('span.dropdown-item-inner');
219
+ var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
220
+ return haystack.startsWith(meta[3].toUpperCase());
221
+ };
222
+
223
+ /**
224
+ * Remove all diatrics from the given text.
225
+ * @access private
226
+ * @param {String} text
227
+ * @returns {String}
228
+ */
229
+ function normalizeToBase(text) {
230
+ var rExps = [
231
+ {re: /[\xC0-\xC6]/g, ch: 'A'},
232
+ {re: /[\xE0-\xE6]/g, ch: 'a'},
233
+ {re: /[\xC8-\xCB]/g, ch: 'E'},
234
+ {re: /[\xE8-\xEB]/g, ch: 'e'},
235
+ {re: /[\xCC-\xCF]/g, ch: 'I'},
236
+ {re: /[\xEC-\xEF]/g, ch: 'i'},
237
+ {re: /[\xD2-\xD6]/g, ch: 'O'},
238
+ {re: /[\xF2-\xF6]/g, ch: 'o'},
239
+ {re: /[\xD9-\xDC]/g, ch: 'U'},
240
+ {re: /[\xF9-\xFC]/g, ch: 'u'},
241
+ {re: /[\xC7-\xE7]/g, ch: 'c'},
242
+ {re: /[\xD1]/g, ch: 'N'},
243
+ {re: /[\xF1]/g, ch: 'n'},
244
+ ];
245
+ $.each(rExps, function() {
246
+ text = text ? text.replace(this.re, this.ch) : '';
247
+ });
248
+ return text;
249
+ }
250
+
251
+ // List of HTML entities for escaping.
252
+ var escapeMap = {
253
+ '&': '&amp;',
254
+ '<': '&lt;',
255
+ '>': '&gt;',
256
+ '"': '&quot;',
257
+ '\'': '&#x27;',
258
+ '`': '&#x60;',
259
+ };
260
+
261
+ var unescapeMap = {
262
+ '&amp;': '&',
263
+ '&lt;': '<',
264
+ '&gt;': '>',
265
+ '&quot;': '"',
266
+ '&#x27;': '\'',
267
+ '&#x60;': '`',
268
+ };
269
+
270
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
271
+ var createEscaper = function(map) {
272
+ var escaper = function(match) {
273
+ return map[match];
274
+ };
275
+ // Regexes for identifying a key that needs to be escaped.
276
+ var source = '(?:' + Object.keys(map).join('|') + ')';
277
+ var testRegexp = RegExp(source);
278
+ var replaceRegexp = RegExp(source, 'g');
279
+ return function(string) {
280
+ string = string == null ? '' : '' + string;
281
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
282
+ };
283
+ };
284
+
285
+ var htmlEscape = createEscaper(escapeMap);
286
+ var htmlUnescape = createEscaper(unescapeMap);
287
+
288
+ var Selectpicker = function(element, options) {
289
+ // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
290
+ if (!valHooks.useDefault) {
291
+ $.valHooks.select.set = valHooks._set;
292
+ valHooks.useDefault = true;
293
+ }
294
+
295
+ this.$element = $(element);
296
+ this.$newElement = null;
297
+ this.$button = null;
298
+ this.$menu = null;
299
+ this.$lis = null;
300
+ this.options = options;
301
+
302
+ // 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
303
+ // data-attribute)
304
+ if (this.options.title === null) {
305
+ this.options.title = this.$element.attr('title');
306
+ }
307
+
308
+ // Format window padding
309
+ var winPad = this.options.windowPadding;
310
+ if (typeof winPad === 'number') {
311
+ this.options.windowPadding = [winPad, winPad, winPad, winPad];
312
+ }
313
+
314
+ //Expose public methods
315
+ this.val = Selectpicker.prototype.val;
316
+ this.render = Selectpicker.prototype.render;
317
+ this.refresh = Selectpicker.prototype.refresh;
318
+ this.setStyle = Selectpicker.prototype.setStyle;
319
+ this.selectAll = Selectpicker.prototype.selectAll;
320
+ this.deselectAll = Selectpicker.prototype.deselectAll;
321
+ this.destroy = Selectpicker.prototype.destroy;
322
+ this.remove = Selectpicker.prototype.remove;
323
+ this.show = Selectpicker.prototype.show;
324
+ this.hide = Selectpicker.prototype.hide;
325
+
326
+ this.init();
327
+ };
328
+
329
+ Selectpicker.VERSION = '1.12.2';
330
+
331
+ // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
332
+ Selectpicker.DEFAULTS = {
333
+ noneSelectedText: 'Nothing selected',
334
+ noneResultsText: 'No results matched {0}',
335
+ countSelectedText: function(numSelected, numTotal) {
336
+ return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
337
+ },
338
+ maxOptionsText: function(numAll, numGroup) {
339
+ return [
340
+ (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
341
+ (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)',
342
+ ];
343
+ },
344
+ selectAllText: 'Select All',
345
+ deselectAllText: 'Deselect All',
346
+ doneButton: false,
347
+ doneButtonText: 'Close',
348
+ multipleSeparator: ', ',
349
+ styleBase: 'btn',
350
+ style: 'btn-default btn-light', // bootstrap4: btn-default replaced by btn-light
351
+ size: 'auto',
352
+ title: null,
353
+ selectedTextFormat: 'values',
354
+ width: false,
355
+ container: false,
356
+ hideDisabled: false,
357
+ showSubtext: false,
358
+ showIcon: true,
359
+ showContent: true,
360
+ dropupAuto: true,
361
+ header: false,
362
+ liveSearch: false,
363
+ liveSearchPlaceholder: null,
364
+ liveSearchNormalize: false,
365
+ liveSearchStyle: 'contains',
366
+ actionsBox: false,
367
+ iconBase: 'fa',
368
+ tickIcon: 'fa-check',
369
+ showTick: false,
370
+ template: {
371
+ caret: '<span class="caret"></span>',
372
+ },
373
+ maxOptions: false,
374
+ mobile: false,
375
+ selectOnTab: false,
376
+ dropdownAlignRight: false,
377
+ windowPadding: 0,
378
+ };
379
+
380
+ Selectpicker.prototype = {
381
+
382
+ constructor: Selectpicker,
383
+
384
+ init: function() {
385
+ var that = this,
386
+ id = this.$element.attr('id');
387
+
388
+ this.$element.addClass('bs-select-hidden');
389
+
390
+ // store originalIndex (key) and newIndex (value) in this.liObj for fast accessibility
391
+ // allows us to do this.$lis.eq(that.liObj[index]) instead of this.$lis.filter('[data-original-index="' + index + '"]')
392
+ this.liObj = {};
393
+ this.multiple = this.$element.prop('multiple');
394
+ this.autofocus = this.$element.prop('autofocus');
395
+ this.$newElement = this.createView();
396
+ this.$element.after(this.$newElement).appendTo(this.$newElement);
397
+ this.$button = this.$newElement.children('button');
398
+ this.$menu = this.$newElement.children('.dropdown-menu');
399
+ this.$menuInner = this.$menu.children('.inner');
400
+ this.$searchbox = this.$menu.find('input');
401
+
402
+ this.$element.removeClass('bs-select-hidden');
403
+
404
+ if (this.options.dropdownAlignRight === true) this.$menu.addClass('dropdown-menu-right');
405
+
406
+ if (typeof id !== 'undefined') {
407
+ this.$button.attr('data-id', id);
408
+ $('label[for="' + id + '"]').click(function(e) {
409
+ e.preventDefault();
410
+ that.$button.focus();
411
+ });
412
+ }
413
+
414
+ this.checkDisabled();
415
+ this.clickListener();
416
+ if (this.options.liveSearch) this.liveSearchListener();
417
+ this.render();
418
+ this.setStyle();
419
+ this.setWidth();
420
+ if (this.options.container) this.selectPosition();
421
+ this.$menu.data('this', this);
422
+ this.$newElement.data('this', this);
423
+ if (this.options.mobile) this.mobile();
424
+
425
+ this.$newElement.on({
426
+ 'hide.bs.dropdown': function(e) {
427
+ that.$menuInner.attr('aria-expanded', false);
428
+ that.$element.trigger('hide.bs.select', e);
429
+ },
430
+ 'hidden.bs.dropdown': function(e) {
431
+ that.$element.trigger('hidden.bs.select', e);
432
+ },
433
+ 'show.bs.dropdown': function(e) {
434
+ that.$menuInner.attr('aria-expanded', true);
435
+ that.$element.trigger('show.bs.select', e);
436
+ },
437
+ 'shown.bs.dropdown': function(e) {
438
+ that.$element.trigger('shown.bs.select', e);
439
+ },
440
+ });
441
+
442
+ if (that.$element[0].hasAttribute('required')) {
443
+ this.$element.on('invalid', function() {
444
+ that.$button.addClass('bs-invalid').focus();
445
+
446
+ that.$element.on({
447
+ 'focus.bs.select': function() {
448
+ that.$button.focus();
449
+ that.$element.off('focus.bs.select');
450
+ },
451
+ 'shown.bs.select': function() {
452
+ that.$element.val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
453
+ .off('shown.bs.select');
454
+ },
455
+ 'rendered.bs.select': function() {
456
+ // if select is no longer invalid, remove the bs-invalid class
457
+ if (this.validity.valid) that.$button.removeClass('bs-invalid');
458
+ that.$element.off('rendered.bs.select');
459
+ },
460
+ });
461
+ });
462
+ }
463
+
464
+ setTimeout(function() {
465
+ that.$element.trigger('loaded.bs.select');
466
+ });
467
+ },
468
+
469
+ createDropdown: function() {
470
+ // Options
471
+ // If we are multiple or showTick option is set, then add the show-tick class
472
+ var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
473
+ inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '',
474
+ autofocus = this.autofocus ? ' autofocus' : '';
475
+ // Elements
476
+ var header = this.options.header ? '<div class="popover-title"><button type="button" class="close" aria-hidden="true">&times;</button>' + this.options.header + '</div>' : '';
477
+ var searchbox = this.options.liveSearch ?
478
+ '<div class="bs-searchbox">' +
479
+ '<input type="text" class="form-control" autocomplete="off"' +
480
+ (null === this.options.liveSearchPlaceholder ? '' : ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"') + ' role="textbox" aria-label="Search">' +
481
+ '</div>'
482
+ : '';
483
+ var actionsbox = this.multiple && this.options.actionsBox ?
484
+ '<div class="bs-actionsbox">' +
485
+ '<div class="btn-group btn-group-sm btn-block">' +
486
+ '<button type="button" class="actions-btn bs-select-all btn btn-default btn-light">' +
487
+ this.options.selectAllText +
488
+ '</button>' +
489
+ '<button type="button" class="actions-btn bs-deselect-all btn btn-default btn-light">' +
490
+ this.options.deselectAllText +
491
+ '</button>' +
492
+ '</div>' +
493
+ '</div>'
494
+ : '';
495
+ var donebutton = this.multiple && this.options.doneButton ?
496
+ '<div class="bs-donebutton">' +
497
+ '<div class="btn-group btn-block">' +
498
+ '<button type="button" class="btn btn-sm btn-default btn-light">' +
499
+ this.options.doneButtonText +
500
+ '</button>' +
501
+ '</div>' +
502
+ '</div>'
503
+ : '';
504
+ var drop =
505
+ '<div class="btn-group bootstrap-select' + showTick + inputGroup + '">' +
506
+ '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" data-toggle="dropdown"' + autofocus + ' role="button">' +
507
+ '<span class="filter-option pull-left"></span>&nbsp;' +
508
+ '<span class="bs-caret">' +
509
+ this.options.template.caret +
510
+ '</span>' +
511
+ '</button>' +
512
+ '<div class="dropdown-menu open" role="combobox">' +
513
+ header +
514
+ searchbox +
515
+ actionsbox +
516
+ '<div class="dropdown-menu inner" role="listbox" aria-expanded="false">' +
517
+ '</div>' +
518
+ donebutton +
519
+ '</div>' +
520
+ '</div>';
521
+
522
+ return $(drop);
523
+ },
524
+
525
+ createView: function() {
526
+ var $drop = this.createDropdown(),
527
+ li = this.createLi();
528
+
529
+ $drop.find('div.inner')[0].innerHTML = li;
530
+ return $drop;
531
+ },
532
+
533
+ reloadLi: function() {
534
+ // rebuild
535
+ var li = this.createLi();
536
+ this.$menuInner[0].innerHTML = li;
537
+ },
538
+
539
+ createLi: function() {
540
+ var that = this,
541
+ _li = [],
542
+ optID = 0,
543
+ titleOption = document.createElement('option'),
544
+ liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure liObj is correct
545
+
546
+ // Helper functions
547
+ /**
548
+ * @param content
549
+ * @param [index]
550
+ * @param [classes]
551
+ * @param [optgroup]
552
+ * @returns {string}
553
+ */
554
+ var generateA = function(content, index, classes, optgroup) {
555
+ classes = 'dropdown-item ' + (classes || '');
556
+ return '<a tabindex="0"' +
557
+ ((typeof classes !== 'undefined' && '' !== classes) ? ' class="' + classes + '"' : '') +
558
+ ((typeof index !== 'undefined' && null !== index) ? ' data-original-index="' + index + '"' : '') +
559
+ ((typeof optgroup !== 'undefined' && null !== optgroup) ? 'data-optgroup="' + optgroup + '"' : '') +
560
+ '>' + content + '</a>';
561
+ };
562
+
563
+ var generateDiv = function(content, classes, optgroup) {
564
+ return '<div' +
565
+ ((typeof classes !== 'undefined' && '' !== classes) ? ' class="' + classes + '"' : '') +
566
+ ((typeof optgroup !== 'undefined' && null !== optgroup) ? ' data-optgroup="' + optgroup + '"' : '') +
567
+ '>' + content + '</div>';
568
+ };
569
+
570
+ /**
571
+ * @param text
572
+ * @param [classes]
573
+ * @param [inline]
574
+ * @param [tokens]
575
+ * @returns {string}
576
+ */
577
+ var generateSpan = function(text, classes, inline, tokens) {
578
+ // support bootstrap v4: http://v4-alpha.getbootstrap.com/components/dropdowns/#single-button-dropdowns
579
+ classes = 'dropdown-item-inner ' + (classes || '');
580
+ return '<span' +
581
+ (typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
582
+ (inline ? ' style="' + inline + '"' : '') +
583
+ (that.options.liveSearchNormalize ? ' data-normalized-text="' + normalizeToBase(htmlEscape($(text).html())) + '"' : '') +
584
+ (typeof tokens !== 'undefined' || tokens !== null ? ' data-tokens="' + tokens + '"' : '') +
585
+ ' role="option">' + text +
586
+ '<span class="' + that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark"></span>' +
587
+ '</span>';
588
+ };
589
+
590
+ if (this.options.title && !this.multiple) {
591
+ // this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased
592
+ // since liObj is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended
593
+ liIndex--;
594
+
595
+ if (!this.$element.find('.bs-title-option').length) {
596
+ // Use native JS to prepend option (faster)
597
+ var element = this.$element[0];
598
+ titleOption.className = 'bs-title-option';
599
+ titleOption.innerHTML = this.options.title;
600
+ titleOption.value = '';
601
+ element.insertBefore(titleOption, element.firstChild);
602
+ // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
603
+ // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
604
+ // if so, the select will have the data-selected attribute
605
+ var $opt = $(element.options[element.selectedIndex]);
606
+ if ($opt.attr('selected') === undefined && this.$element.data('selected') === undefined) {
607
+ titleOption.selected = true;
608
+ }
609
+ }
610
+ }
611
+
612
+ var $selectOptions = this.$element.find('option');
613
+
614
+ $selectOptions.each(function(index) {
615
+ var $this = $(this);
616
+
617
+ liIndex++;
618
+
619
+ if ($this.hasClass('bs-title-option')) return;
620
+
621
+ // Get the class and text for the option
622
+ var optionClass = this.className || '',
623
+ inline = htmlEscape(this.style.cssText),
624
+ text = $this.data('content') ? $this.data('content') : $this.html(),
625
+ tokens = $this.data('tokens') ? $this.data('tokens') : null,
626
+ subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $this.data('subtext') + '</small>' : '',
627
+ icon = typeof $this.data('icon') !== 'undefined' ? '<span class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></span> ' : '',
628
+ $parent = $this.parent(),
629
+ isOptgroup = $parent[0].tagName === 'OPTGROUP',
630
+ isOptgroupDisabled = isOptgroup && $parent[0].disabled,
631
+ isDisabled = this.disabled || isOptgroupDisabled,
632
+ prevHiddenIndex;
633
+
634
+ if (icon !== '' && isDisabled) {
635
+ icon = '<span>' + icon + '</span>';
636
+ }
637
+
638
+ if (that.options.hideDisabled && (isDisabled && !isOptgroup || isOptgroupDisabled)) {
639
+ // set prevHiddenIndex - the index of the first hidden option in a group of hidden options
640
+ // used to determine whether or not a divider should be placed after an optgroup if there are
641
+ // hidden options between the optgroup and the first visible option
642
+ prevHiddenIndex = $this.data('prevHiddenIndex');
643
+ $this.next().data('prevHiddenIndex', (prevHiddenIndex !== undefined ? prevHiddenIndex : index));
644
+
645
+ liIndex--;
646
+ return;
647
+ }
648
+
649
+ if (!$this.data('content')) {
650
+ // Prepend any icon and append any subtext to the main text.
651
+ text = icon + '<span class="text">' + text + subtext + '</span>';
652
+ }
653
+
654
+ if (isOptgroup && $this.data('divider') !== true) {
655
+ if (that.options.hideDisabled && isDisabled) {
656
+ if ($parent.data('allOptionsDisabled') === undefined) {
657
+ var $options = $parent.children();
658
+ $parent.data('allOptionsDisabled', $options.filter(':disabled').length === $options.length);
659
+ }
660
+
661
+ if ($parent.data('allOptionsDisabled')) {
662
+ liIndex--;
663
+ return;
664
+ }
665
+ }
666
+
667
+ var optGroupClass = ' ' + $parent[0].className || '';
668
+
669
+ if ($this.index() === 0) { // Is it the first option of the optgroup?
670
+ optID += 1;
671
+
672
+ // Get the opt group label
673
+ var label = $parent[0].label,
674
+ labelSubtext = typeof $parent.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $parent.data('subtext') + '</small>' : '',
675
+ labelIcon = $parent.data('icon') ? '<span class="' + that.options.iconBase + ' ' + $parent.data('icon') + '"></span> ' : '';
676
+
677
+ label = labelIcon + '<span class="text">' + htmlEscape(label) + labelSubtext + '</span>';
678
+
679
+ if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?
680
+ liIndex++;
681
+ _li.push(generateDiv('', 'dropdown-divider', optID + 'div'));
682
+ }
683
+ liIndex++;
684
+ _li.push(generateDiv(label, 'dropdown-header' + optGroupClass, optID));
685
+ }
686
+
687
+ if (that.options.hideDisabled && isDisabled) {
688
+ liIndex--;
689
+ return;
690
+ }
691
+
692
+ _li.push(generateA(generateSpan(text, 'opt ' + optionClass + optGroupClass, inline, tokens), index, '', optID));
693
+ } else if ($this.data('divider') === true) {
694
+ _li.push(generateDiv('', 'dropdown-divider', optID + 'div'));
695
+ } else if ($this.data('hidden') === true) {
696
+ // set prevHiddenIndex - the index of the first hidden option in a group of hidden options
697
+ // used to determine whether or not a divider should be placed after an optgroup if there are
698
+ // hidden options between the optgroup and the first visible option
699
+ prevHiddenIndex = $this.data('prevHiddenIndex');
700
+ $this.next().data('prevHiddenIndex', (prevHiddenIndex !== undefined ? prevHiddenIndex : index));
701
+
702
+ _li.push(generateA(generateSpan(text, optionClass, inline, tokens), index, 'hidden is-hidden'));
703
+ } else {
704
+ var showDivider = this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP';
705
+
706
+ // if previous element is not an optgroup and hideDisabled is true
707
+ if (!showDivider && that.options.hideDisabled) {
708
+ prevHiddenIndex = $this.data('prevHiddenIndex');
709
+
710
+ if (prevHiddenIndex !== undefined) {
711
+ // select the element **before** the first hidden element in the group
712
+ var prevHidden = $selectOptions.eq(prevHiddenIndex)[0].previousElementSibling;
713
+
714
+ if (prevHidden && prevHidden.tagName === 'OPTGROUP' && !prevHidden.disabled) {
715
+ showDivider = true;
716
+ }
717
+ }
718
+ }
719
+
720
+ if (showDivider) {
721
+ liIndex++;
722
+ _li.push(generateDiv('', 'dropdown-divider', optID + 'div'));
723
+ }
724
+ _li.push(generateA(generateSpan(text, optionClass, inline, tokens), index));
725
+ }
726
+
727
+ that.liObj[index] = liIndex;
728
+ });
729
+
730
+ //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button
731
+ if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {
732
+ this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
733
+ }
734
+
735
+ return _li.join('');
736
+ },
737
+
738
+ findLis: function() {
739
+ if (this.$lis == null) this.$lis = this.$menu.find('a, .dropdown-header, .dropdown-divider');
740
+ return this.$lis;
741
+ },
742
+
743
+ /**
744
+ * @param [updateLi] defaults to true
745
+ */
746
+ render: function(updateLi) {
747
+ var that = this,
748
+ notDisabled,
749
+ $selectOptions = this.$element.find('option');
750
+
751
+ //Update the LI to match the SELECT
752
+ if (updateLi !== false) {
753
+ $selectOptions.each(function(index) {
754
+ var $lis = that.findLis().eq(that.liObj[index]);
755
+
756
+ that.setDisabled(index, this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled, $lis);
757
+ that.setSelected(index, this.selected, $lis);
758
+ });
759
+ }
760
+
761
+ this.togglePlaceholder();
762
+
763
+ this.tabIndex();
764
+
765
+ var selectedItems = $selectOptions.map(function() {
766
+ if (this.selected) {
767
+ if (that.options.hideDisabled && (this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled)) return;
768
+
769
+ var $this = $(this),
770
+ icon = $this.data('icon') && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '',
771
+ subtext;
772
+
773
+ if (that.options.showSubtext && $this.data('subtext') && !that.multiple) {
774
+ subtext = ' <small class="text-muted">' + $this.data('subtext') + '</small>';
775
+ } else {
776
+ subtext = '';
777
+ }
778
+ if (typeof $this.attr('title') !== 'undefined') {
779
+ return $this.attr('title');
780
+ } else if ($this.data('content') && that.options.showContent) {
781
+ return $this.data('content').toString();
782
+ } else {
783
+ return icon + $this.html() + subtext;
784
+ }
785
+ }
786
+ }).toArray();
787
+
788
+ //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled
789
+ //Convert all the values into a comma delimited string
790
+ var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);
791
+
792
+ //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
793
+ if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {
794
+ var max = this.options.selectedTextFormat.split('>');
795
+ if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) {
796
+ notDisabled = this.options.hideDisabled ? ', [disabled]' : '';
797
+ var totalCount = $selectOptions.not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length,
798
+ tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText;
799
+ title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString());
800
+ }
801
+ }
802
+
803
+ if (this.options.title == undefined) {
804
+ this.options.title = this.$element.attr('title');
805
+ }
806
+
807
+ if (this.options.selectedTextFormat == 'static') {
808
+ title = this.options.title;
809
+ }
810
+
811
+ //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
812
+ if (!title) {
813
+ title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;
814
+ }
815
+
816
+ //strip all HTML tags and trim the result, then unescape any escaped tags
817
+ this.$button.attr('title', htmlUnescape($.trim(title.replace(/<[^>]*>?/g, ''))));
818
+ this.$button.children('.filter-option').html(title);
819
+
820
+ this.$element.trigger('rendered.bs.select');
821
+ },
822
+
823
+ /**
824
+ * @param [style]
825
+ * @param [status]
826
+ */
827
+ setStyle: function(style, status) {
828
+ if (this.$element.attr('class')) {
829
+ this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
830
+ }
831
+
832
+ var buttonClass = style ? style : this.options.style;
833
+
834
+ if (status == 'add') {
835
+ this.$button.addClass(buttonClass);
836
+ } else if (status == 'remove') {
837
+ this.$button.removeClass(buttonClass);
838
+ } else {
839
+ this.$button.removeClass(this.options.style);
840
+ this.$button.addClass(buttonClass);
841
+ }
842
+ },
843
+ updatePosition: function() {
844
+ // this fixes https://github.com/heimrichhannot/bootstrap-select/issues/4
845
+ var event = this.$menu.get(0).ownerDocument.createEvent('HTMLEvents');
846
+ event.initEvent('resize', true, false);
847
+ this.$menu.get(0).ownerDocument.dispatchEvent(event);
848
+ },
849
+ liHeight: function(refresh) {
850
+ if (!refresh && (this.options.size === false || this.sizeInfo)) return;
851
+
852
+ var newElement = document.createElement('div'),
853
+ menu = document.createElement('div'),
854
+ menuInner = document.createElement('ul'),
855
+ divider = document.createElement('a'),
856
+ li = document.createElement('a'),
857
+ a = document.createElement('span'),
858
+ text = document.createElement('span'),
859
+ header = this.options.header && this.$menu.find('.popover-title').length > 0 ? this.$menu.find('.popover-title')[0].cloneNode(true) : null,
860
+ search = this.options.liveSearch ? document.createElement('div') : null,
861
+ actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
862
+ doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null;
863
+
864
+ text.className = 'text';
865
+ newElement.className = this.$menu[0].parentNode.className + ' show open'; // bootstrap 4 requires show instead of open
866
+ menu.className = 'dropdown-menu open show';
867
+ menuInner.className = 'dropdown-menu inner';
868
+ divider.className = 'dropdown-divider';
869
+ a.className = 'dropdown-item-inner';
870
+
871
+ text.appendChild(document.createTextNode('Inner text'));
872
+
873
+ a.appendChild(text);
874
+ li.appendChild(a);
875
+ menuInner.appendChild(li);
876
+ menuInner.appendChild(divider);
877
+ if (header) menu.appendChild(header);
878
+ if (search) {
879
+ var input = document.createElement('input');
880
+ search.className = 'bs-searchbox';
881
+ input.className = 'form-control';
882
+ search.appendChild(input);
883
+ menu.appendChild(search);
884
+ }
885
+ if (actions) menu.appendChild(actions);
886
+ menu.appendChild(menuInner);
887
+ if (doneButton) menu.appendChild(doneButton);
888
+ newElement.appendChild(menu);
889
+
890
+ document.body.appendChild(newElement);
891
+
892
+ var liHeight = a.offsetHeight,
893
+ headerHeight = header ? header.offsetHeight : 0,
894
+ searchHeight = search ? search.offsetHeight : 0,
895
+ actionsHeight = actions ? actions.offsetHeight : 0,
896
+ doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
897
+ dividerHeight = $(divider).outerHeight(true),
898
+ // fall back to jQuery if getComputedStyle is not supported
899
+ menuStyle = typeof getComputedStyle === 'function' ? getComputedStyle(menu) : false,
900
+ $menu = menuStyle ? null : $(menu),
901
+ menuPadding = {
902
+ vert: parseInt(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +
903
+ parseInt(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +
904
+ parseInt(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +
905
+ parseInt(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),
906
+ horiz: parseInt(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +
907
+ parseInt(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +
908
+ parseInt(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +
909
+ parseInt(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth')),
910
+ },
911
+ menuExtras = {
912
+ vert: menuPadding.vert +
913
+ parseInt(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +
914
+ parseInt(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,
915
+ horiz: menuPadding.horiz +
916
+ parseInt(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +
917
+ parseInt(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2,
918
+ };
919
+
920
+ document.body.removeChild(newElement);
921
+
922
+ this.sizeInfo = {
923
+ liHeight: liHeight,
924
+ headerHeight: headerHeight,
925
+ searchHeight: searchHeight,
926
+ actionsHeight: actionsHeight,
927
+ doneButtonHeight: doneButtonHeight,
928
+ dividerHeight: dividerHeight,
929
+ menuPadding: menuPadding,
930
+ menuExtras: menuExtras,
931
+ };
932
+ },
933
+
934
+ setSize: function() {
935
+ this.findLis();
936
+ this.liHeight();
937
+
938
+ if (this.options.header) this.$menu.css('padding-top', 0);
939
+ if (this.options.size === false) return;
940
+
941
+ var that = this,
942
+ $menu = this.$menu,
943
+ $menuInner = this.$menuInner,
944
+ $window = $(window),
945
+ selectHeight = this.$newElement[0].offsetHeight,
946
+ selectWidth = this.$newElement[0].offsetWidth,
947
+ liHeight = this.sizeInfo['liHeight'],
948
+ headerHeight = this.sizeInfo['headerHeight'],
949
+ searchHeight = this.sizeInfo['searchHeight'],
950
+ actionsHeight = this.sizeInfo['actionsHeight'],
951
+ doneButtonHeight = this.sizeInfo['doneButtonHeight'],
952
+ divHeight = this.sizeInfo['dividerHeight'],
953
+ menuPadding = this.sizeInfo['menuPadding'],
954
+ menuExtras = this.sizeInfo['menuExtras'],
955
+ notDisabled = this.options.hideDisabled ? '.disabled' : '',
956
+ menuHeight,
957
+ menuWidth,
958
+ getHeight,
959
+ getWidth,
960
+ selectOffsetTop,
961
+ selectOffsetBot,
962
+ selectOffsetLeft,
963
+ selectOffsetRight,
964
+ getPos = function() {
965
+ var pos = that.$newElement.offset(),
966
+ $container = $(that.options.container),
967
+ containerPos;
968
+
969
+ if (that.options.container && !$container.is('body')) {
970
+ containerPos = $container.offset();
971
+ containerPos.top += parseInt($container.css('borderTopWidth'));
972
+ containerPos.left += parseInt($container.css('borderLeftWidth'));
973
+ } else {
974
+ containerPos = {top: 0, left: 0};
975
+ }
976
+
977
+ var winPad = that.options.windowPadding;
978
+ selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
979
+ selectOffsetBot = $window.height() - selectOffsetTop - selectHeight - containerPos.top - winPad[2];
980
+ selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
981
+ selectOffsetRight = $window.width() - selectOffsetLeft - selectWidth - containerPos.left - winPad[1];
982
+ selectOffsetTop -= winPad[0];
983
+ selectOffsetLeft -= winPad[3];
984
+ };
985
+
986
+ getPos();
987
+
988
+ if (this.options.size === 'auto') {
989
+ var getSize = function() {
990
+ var minHeight,
991
+ hasClass = function(className, include) {
992
+ return function(element) {
993
+ if (include) {
994
+ return (element.classList ? element.classList.contains(className) : $(element).hasClass(className));
995
+ } else {
996
+ return !(element.classList ? element.classList.contains(className) : $(element).hasClass(className));
997
+ }
998
+ };
999
+ },
1000
+ lis = that.$menuInner[0].getElementsByTagName('a'),
1001
+ lisVisible = Array.prototype.filter ? Array.prototype.filter.call(lis, hasClass('d-none', false)) : that.$lis.not('.d-none'),
1002
+ optGroup = Array.prototype.filter ? Array.prototype.filter.call(lisVisible, hasClass('dropdown-header', true)) : lisVisible.filter('.dropdown-header');
1003
+
1004
+ getPos();
1005
+ menuHeight = selectOffsetBot - menuExtras.vert;
1006
+ menuWidth = selectOffsetRight - menuExtras.horiz;
1007
+
1008
+ if (that.options.container) {
1009
+ if (!$menu.data('height')) $menu.data('height', $menu.height());
1010
+ getHeight = $menu.data('height');
1011
+
1012
+ if (!$menu.data('width')) $menu.data('width', $menu.width());
1013
+ getWidth = $menu.data('width');
1014
+ } else {
1015
+ getHeight = $menu.height();
1016
+ getWidth = $menu.width();
1017
+ }
1018
+
1019
+ if (that.options.dropupAuto) {
1020
+ that.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
1021
+ }
1022
+
1023
+ if (that.$newElement.hasClass('dropup')) {
1024
+ menuHeight = selectOffsetTop - menuExtras.vert;
1025
+ }
1026
+
1027
+ if (that.options.dropdownAlignRight === 'auto') {
1028
+ $menu.toggleClass('dropdown-menu-right', selectOffsetLeft > selectOffsetRight && (menuWidth - menuExtras.horiz) < (getWidth - selectWidth));
1029
+ }
1030
+
1031
+ if ((lisVisible.length + optGroup.length) > 3) {
1032
+ minHeight = liHeight * 3 + menuExtras.vert - 2;
1033
+ } else {
1034
+ minHeight = 0;
1035
+ }
1036
+
1037
+ $menu.css({
1038
+ 'max-height': menuHeight + 'px',
1039
+ 'overflow': 'hidden',
1040
+ 'min-height': minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px',
1041
+ });
1042
+ $menuInner.css({
1043
+ 'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert + 'px',
1044
+ 'overflow-y': 'auto',
1045
+ 'min-height': Math.max(minHeight - menuPadding.vert, 0) + 'px',
1046
+ });
1047
+ };
1048
+ getSize();
1049
+ this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);
1050
+ $window.off('resize.getSize scroll.getSize').on('resize.getSize scroll.getSize', getSize);
1051
+ } else if (this.options.size && this.options.size != 'auto' && this.$lis.not(notDisabled).length > this.options.size) {
1052
+ var optIndex = this.$lis.not('.dropdown-divider').not(notDisabled).children().slice(0, this.options.size).last().parent().index(),
1053
+ divLength = this.$lis.slice(0, optIndex + 1).filter('.dropdown-divider').length;
1054
+ menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
1055
+
1056
+ if (that.options.container) {
1057
+ if (!$menu.data('height')) $menu.data('height', $menu.height());
1058
+ getHeight = $menu.data('height');
1059
+ } else {
1060
+ getHeight = $menu.height();
1061
+ }
1062
+
1063
+ if (that.options.dropupAuto) {
1064
+ //noinspection JSUnusedAssignment
1065
+ this.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
1066
+ }
1067
+ $menu.css({
1068
+ 'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px',
1069
+ 'overflow': 'hidden',
1070
+ 'min-height': '',
1071
+ });
1072
+ $menuInner.css({
1073
+ 'max-height': menuHeight - menuPadding.vert + 'px',
1074
+ 'overflow-y': 'auto',
1075
+ 'min-height': '',
1076
+ });
1077
+ }
1078
+ },
1079
+
1080
+ setWidth: function() {
1081
+ if (this.options.width === 'auto') {
1082
+ this.$menu.css('min-width', '0');
1083
+
1084
+ // Get correct width if element is hidden
1085
+ var $selectClone = this.$menu.parent().clone().appendTo('body'),
1086
+ $selectClone2 = this.options.container ? this.$newElement.clone().appendTo('body') : $selectClone,
1087
+ ulWidth = $selectClone.children('.dropdown-menu').outerWidth(),
1088
+ btnWidth = $selectClone2.css('width', 'auto').children('button').outerWidth();
1089
+
1090
+ $selectClone.remove();
1091
+ $selectClone2.remove();
1092
+
1093
+ // Set width to whatever's larger, button title or longest option
1094
+ this.$newElement.css('width', Math.max(ulWidth, btnWidth) + 'px');
1095
+ } else if (this.options.width === 'fit') {
1096
+ // Remove inline min-width so width can be changed from 'auto'
1097
+ this.$menu.css('min-width', '');
1098
+ this.$newElement.css('width', '').addClass('fit-width');
1099
+ } else if (this.options.width) {
1100
+ // Remove inline min-width so width can be changed from 'auto'
1101
+ this.$menu.css('min-width', '');
1102
+ this.$newElement.css('width', this.options.width);
1103
+ } else {
1104
+ // Remove inline min-width/width so width can be changed
1105
+ this.$menu.css('min-width', '');
1106
+ this.$newElement.css('width', '');
1107
+ }
1108
+ // Remove fit-width class if width is changed programmatically
1109
+ if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
1110
+ this.$newElement.removeClass('fit-width');
1111
+ }
1112
+ },
1113
+
1114
+ selectPosition: function() {
1115
+ this.$bsContainer = $('<div class="bs-container" />');
1116
+
1117
+ var that = this,
1118
+ $container = $(this.options.container),
1119
+ pos,
1120
+ containerPos,
1121
+ actualHeight,
1122
+ getPlacement = function($element) {
1123
+ that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));
1124
+ pos = $element.offset();
1125
+
1126
+ if (!$container.is('body')) {
1127
+ containerPos = $container.offset();
1128
+ containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
1129
+ containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
1130
+ } else {
1131
+ containerPos = {top: 0, left: 0};
1132
+ }
1133
+
1134
+ actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;
1135
+
1136
+ that.$bsContainer.css({
1137
+ 'top': pos.top - containerPos.top + actualHeight,
1138
+ 'left': pos.left - containerPos.left,
1139
+ 'width': $element[0].offsetWidth,
1140
+ });
1141
+ };
1142
+
1143
+ this.$button.on('click', function() {
1144
+ var $this = $(this);
1145
+
1146
+ if (that.isDisabled()) {
1147
+ return;
1148
+ }
1149
+
1150
+ getPlacement(that.$newElement);
1151
+
1152
+ that.$bsContainer.appendTo(that.options.container).toggleClass('open', !$this.hasClass('open')).append(that.$menu);
1153
+ });
1154
+
1155
+ $(window).on('resize scroll', function() {
1156
+ getPlacement(that.$newElement);
1157
+ });
1158
+
1159
+ this.$element.on('hide.bs.select', function() {
1160
+ that.$menu.data('height', that.$menu.height());
1161
+ that.$bsContainer.detach();
1162
+ });
1163
+ },
1164
+
1165
+ /**
1166
+ * @param {number} index - the index of the option that is being changed
1167
+ * @param {boolean} selected - true if the option is being selected, false if being deselected
1168
+ * @param {JQuery} $lis - the 'li' element that is being modified
1169
+ */
1170
+ setSelected: function(index, selected, $lis) {
1171
+ if (!$lis) {
1172
+ this.togglePlaceholder(); // check if setSelected is being called by changing the value of the select
1173
+ $lis = this.findLis().eq(this.liObj[index]);
1174
+ }
1175
+
1176
+ $lis.toggleClass('selected', selected).find('span.dropdown-item-inner').attr('aria-selected', selected);
1177
+ },
1178
+
1179
+ /**
1180
+ * @param {number} index - the index of the option that is being disabled
1181
+ * @param {boolean} disabled - true if the option is being disabled, false if being enabled
1182
+ * @param {JQuery} $lis - the 'li' element that is being modified
1183
+ */
1184
+ setDisabled: function(index, disabled, $lis) {
1185
+ if (!$lis) {
1186
+ $lis = this.findLis().eq(this.liObj[index]);
1187
+ }
1188
+
1189
+ if (disabled) {
1190
+ $lis.addClass('disabled').children('span.dropdown-item-inner').attr('href', '#').attr('tabindex', -1).attr('aria-disabled', true);
1191
+ } else {
1192
+ $lis.removeClass('disabled').children('span.dropdown-item-inner').removeAttr('href').attr('tabindex', 0).attr('aria-disabled', false);
1193
+ }
1194
+ },
1195
+
1196
+ isDisabled: function() {
1197
+ return this.$element[0].disabled;
1198
+ },
1199
+
1200
+ checkDisabled: function() {
1201
+ var that = this;
1202
+
1203
+ if (this.isDisabled()) {
1204
+ this.$newElement.addClass('disabled');
1205
+ this.$button.addClass('disabled').attr('tabindex', -1).attr('aria-disabled', true);
1206
+ } else {
1207
+ if (this.$button.hasClass('disabled')) {
1208
+ this.$newElement.removeClass('disabled');
1209
+ this.$button.removeClass('disabled').attr('aria-disabled', false);
1210
+ }
1211
+
1212
+ if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {
1213
+ this.$button.removeAttr('tabindex');
1214
+ }
1215
+ }
1216
+
1217
+ this.$button.click(function() {
1218
+ return !that.isDisabled();
1219
+ });
1220
+ },
1221
+
1222
+ togglePlaceholder: function() {
1223
+ var value = this.$element.val();
1224
+ this.$button.toggleClass('bs-placeholder', value === null || value === '' || (value.constructor === Array && value.length === 0));
1225
+ },
1226
+
1227
+ tabIndex: function() {
1228
+ if (this.$element.data('tabindex') !== this.$element.attr('tabindex') &&
1229
+ (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {
1230
+ this.$element.data('tabindex', this.$element.attr('tabindex'));
1231
+ this.$button.attr('tabindex', this.$element.data('tabindex'));
1232
+ }
1233
+
1234
+ this.$element.attr('tabindex', -98);
1235
+ },
1236
+
1237
+ clickListener: function() {
1238
+ var that = this,
1239
+ $document = $(document);
1240
+
1241
+ $document.data('spaceSelect', false);
1242
+
1243
+ this.$button.on('keyup', function(e) {
1244
+ if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
1245
+ e.preventDefault();
1246
+ $document.data('spaceSelect', false);
1247
+ }
1248
+ });
1249
+
1250
+ this.$button.on('click', function() {
1251
+ that.setSize();
1252
+ });
1253
+
1254
+ this.$element.on('shown.bs.select', function() {
1255
+ if (!that.options.liveSearch && !that.multiple) {
1256
+ that.$menuInner.find('a.selected').focus();
1257
+ } else if (!that.multiple) {
1258
+ var selectedIndex = that.liObj[that.$element[0].selectedIndex];
1259
+
1260
+ if (typeof selectedIndex !== 'number' || that.options.size === false) return;
1261
+
1262
+ // scroll to selected option
1263
+ var offset = that.$lis.eq(selectedIndex)[0].offsetTop - that.$menuInner[0].offsetTop;
1264
+ offset = offset - that.$menuInner[0].offsetHeight / 2 + that.sizeInfo.liHeight / 2;
1265
+ that.$menuInner[0].scrollTop = offset;
1266
+ }
1267
+ });
1268
+
1269
+ this.$menuInner.on('click', 'a', function(e) {
1270
+ var $this = $(this).find('span.dropdown-item-inner'),
1271
+ clickedIndex = $this.parent().data('originalIndex'),
1272
+ prevValue = that.$element.val(),
1273
+ prevIndex = that.$element.prop('selectedIndex'),
1274
+ triggerChange = true;
1275
+
1276
+ // Don't close on multi choice menu
1277
+ if (that.multiple && that.options.maxOptions !== 1) {
1278
+ e.stopPropagation();
1279
+ }
1280
+
1281
+ e.preventDefault();
1282
+
1283
+ //Don't run if we have been disabled
1284
+ if (!that.isDisabled() && !$this.parent().hasClass('disabled')) {
1285
+ var $options = that.$element.find('option'),
1286
+ $option = $options.eq(clickedIndex),
1287
+ state = $option.prop('selected'),
1288
+ $optgroup = $option.parent('optgroup'),
1289
+ maxOptions = that.options.maxOptions,
1290
+ maxOptionsGrp = $optgroup.data('maxOptions') || false;
1291
+
1292
+ if (!that.multiple) { // Deselect all others if not multi select box
1293
+ $options.prop('selected', false);
1294
+ $option.prop('selected', true);
1295
+ that.$menuInner.find('.selected').removeClass('selected').find('span.dropdown-item-inner').attr('aria-selected', false);
1296
+ that.setSelected(clickedIndex, true);
1297
+ } else { // Toggle the one we have chosen if we are multi select.
1298
+ $option.prop('selected', !state);
1299
+ that.setSelected(clickedIndex, !state);
1300
+ $this.blur();
1301
+
1302
+ if (maxOptions !== false || maxOptionsGrp !== false) {
1303
+ var maxReached = maxOptions < $options.filter(':selected').length,
1304
+ maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;
1305
+
1306
+ if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
1307
+ if (maxOptions && maxOptions == 1) {
1308
+ $options.prop('selected', false);
1309
+ $option.prop('selected', true);
1310
+ that.$menuInner.find('.selected').removeClass('selected');
1311
+ that.setSelected(clickedIndex, true);
1312
+ } else if (maxOptionsGrp && maxOptionsGrp == 1) {
1313
+ $optgroup.find('option:selected').prop('selected', false);
1314
+ $option.prop('selected', true);
1315
+ var optgroupID = $this.parent().data('optgroup');
1316
+ that.$menuInner.find('[data-optgroup="' + optgroupID + '"]').removeClass('selected');
1317
+ that.setSelected(clickedIndex, true);
1318
+ } else {
1319
+ var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
1320
+ maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
1321
+ maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
1322
+ maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
1323
+ $notify = $('<div class="notify"></div>');
1324
+ // If {var} is set in array, replace it
1325
+ /** @deprecated */
1326
+ if (maxOptionsArr[2]) {
1327
+ maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
1328
+ maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
1329
+ }
1330
+
1331
+ $option.prop('selected', false);
1332
+
1333
+ that.$menu.append($notify);
1334
+
1335
+ if (maxOptions && maxReached) {
1336
+ $notify.append($('<div>' + maxTxt + '</div>'));
1337
+ triggerChange = false;
1338
+ that.$element.trigger('maxReached.bs.select');
1339
+ }
1340
+
1341
+ if (maxOptionsGrp && maxReachedGrp) {
1342
+ $notify.append($('<div>' + maxTxtGrp + '</div>'));
1343
+ triggerChange = false;
1344
+ that.$element.trigger('maxReachedGrp.bs.select');
1345
+ }
1346
+
1347
+ setTimeout(function() {
1348
+ that.setSelected(clickedIndex, false);
1349
+ }, 10);
1350
+
1351
+ $notify.delay(750).fadeOut(300, function() {
1352
+ $(this).remove();
1353
+ });
1354
+ }
1355
+ }
1356
+ }
1357
+ }
1358
+
1359
+ if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
1360
+ that.$button.focus();
1361
+ } else if (that.options.liveSearch) {
1362
+ that.$searchbox.focus();
1363
+ }
1364
+
1365
+ // Trigger select 'change'
1366
+ if (triggerChange) {
1367
+ if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
1368
+ // $option.prop('selected') is current option state (selected/unselected). state is previous option state.
1369
+ changed_arguments = [clickedIndex, $option.prop('selected'), state];
1370
+ that.$element.triggerNative('change');
1371
+ }
1372
+ }
1373
+ }
1374
+ });
1375
+
1376
+ this.$menu.on('click', 'a.disabled span.dropdown-item-inner , .popover-title, .popover-title :not(.close)', function(e) {
1377
+ if (e.currentTarget == this) {
1378
+ e.preventDefault();
1379
+ e.stopPropagation();
1380
+ if (that.options.liveSearch && !$(e.target).hasClass('close')) {
1381
+ that.$searchbox.focus();
1382
+ } else {
1383
+ that.$button.focus();
1384
+ }
1385
+ }
1386
+ });
1387
+
1388
+ this.$menuInner.on('click', '.dropdown-divider, .dropdown-header', function(e) {
1389
+ e.preventDefault();
1390
+ e.stopPropagation();
1391
+ if (that.options.liveSearch) {
1392
+ that.$searchbox.focus();
1393
+ } else {
1394
+ that.$button.focus();
1395
+ }
1396
+ });
1397
+
1398
+ this.$menu.on('click', '.popover-title .close', function() {
1399
+ that.$button.click();
1400
+ });
1401
+
1402
+ this.$searchbox.on('click', function(e) {
1403
+ e.stopPropagation();
1404
+ });
1405
+
1406
+ this.$menu.on('click', '.actions-btn', function(e) {
1407
+ if (that.options.liveSearch) {
1408
+ that.$searchbox.focus();
1409
+ } else {
1410
+ that.$button.focus();
1411
+ }
1412
+
1413
+ e.preventDefault();
1414
+ e.stopPropagation();
1415
+
1416
+ if ($(this).hasClass('bs-select-all')) {
1417
+ that.selectAll();
1418
+ } else {
1419
+ that.deselectAll();
1420
+ }
1421
+ });
1422
+
1423
+ this.$element.change(function() {
1424
+ that.render(false);
1425
+ that.$element.trigger('changed.bs.select', changed_arguments);
1426
+ changed_arguments = null;
1427
+ });
1428
+ },
1429
+
1430
+ liveSearchListener: function() {
1431
+ var that = this,
1432
+ $no_results = $('<li class="no-results"></li>');
1433
+
1434
+ this.$button.on('click.dropdown.data-api', function() {
1435
+ that.$menuInner.find('.active').removeClass('active');
1436
+ if (!!that.$searchbox.val()) {
1437
+ that.$searchbox.val('');
1438
+ that.$lis.not('.is-hidden').removeClass('d-none');
1439
+ if (!!$no_results.parent().length) $no_results.remove();
1440
+ }
1441
+ if (!that.multiple) that.$menuInner.find('.selected').addClass('active');
1442
+ setTimeout(function() {
1443
+ that.$searchbox.focus();
1444
+ }, 10);
1445
+ });
1446
+
1447
+ this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function(e) {
1448
+ e.stopPropagation();
1449
+ });
1450
+
1451
+ this.$searchbox.on('input propertychange', function() {
1452
+ that.$lis.not('.is-hidden').removeClass('d-none');
1453
+ that.$lis.filter('.active').removeClass('active');
1454
+ $no_results.remove();
1455
+
1456
+ if (that.$searchbox.val()) {
1457
+ var $searchBase = that.$lis.not('.is-hidden, .dropdown-divider, .dropdown-header'),
1458
+ $hideItems;
1459
+
1460
+ if (that.options.liveSearchNormalize) {
1461
+ $hideItems = $searchBase.not(':a' + that._searchStyle() + '("' + normalizeToBase(that.$searchbox.val()) + '")');
1462
+ } else {
1463
+ $hideItems = $searchBase.not(':' + that._searchStyle() + '("' + that.$searchbox.val() + '")');
1464
+ }
1465
+
1466
+ if ($hideItems.length === $searchBase.length) {
1467
+ $no_results.html(that.options.noneResultsText.replace('{0}', '"' + htmlEscape(that.$searchbox.val()) + '"'));
1468
+ that.$menuInner.append($no_results);
1469
+ that.$lis.addClass('d-none');
1470
+ } else {
1471
+ $hideItems.addClass('d-none');
1472
+
1473
+ var $lisVisible = that.$lis.not('.d-none'),
1474
+ $foundDiv;
1475
+
1476
+ // hide divider if first or last visible, or if followed by another divider
1477
+ $lisVisible.each(function(index) {
1478
+ var $this = $(this);
1479
+
1480
+ if ($this.hasClass('dropdown-divider')) {
1481
+ if ($foundDiv === undefined) {
1482
+ $this.addClass('d-none');
1483
+ } else {
1484
+ if ($foundDiv) $foundDiv.addClass('d-none');
1485
+ $foundDiv = $this;
1486
+ }
1487
+ } else if ($this.hasClass('dropdown-header') && $lisVisible.eq(index + 1).data('optgroup') !== $this.data('optgroup')) {
1488
+ $this.addClass('d-none');
1489
+ } else {
1490
+ $foundDiv = null;
1491
+ }
1492
+ });
1493
+ if ($foundDiv) $foundDiv.addClass('d-none');
1494
+
1495
+ $searchBase.not('.d-none').first().addClass('active');
1496
+ that.$menuInner.scrollTop(0);
1497
+ }
1498
+
1499
+ that.updatePosition();
1500
+ }
1501
+ });
1502
+ },
1503
+
1504
+ _searchStyle: function() {
1505
+ var styles = {
1506
+ begins: 'ibegins',
1507
+ startsWith: 'ibegins',
1508
+ };
1509
+
1510
+ return styles[this.options.liveSearchStyle] || 'icontains';
1511
+ },
1512
+
1513
+ val: function(value) {
1514
+ if (typeof value !== 'undefined') {
1515
+ this.$element.val(value);
1516
+ this.render();
1517
+
1518
+ return this.$element;
1519
+ } else {
1520
+ return this.$element.val();
1521
+ }
1522
+ },
1523
+
1524
+ changeAll: function(status) {
1525
+ if (!this.multiple) return;
1526
+ if (typeof status === 'undefined') status = true;
1527
+
1528
+ this.findLis();
1529
+
1530
+ var $options = this.$element.find('option'),
1531
+ $lisVisible = this.$lis.not('.dropdown-divider, .dropdown-header, .disabled, .d-none'),
1532
+ lisVisLen = $lisVisible.length,
1533
+ selectedOptions = [];
1534
+
1535
+ if (status) {
1536
+ if ($lisVisible.filter('.selected').length === $lisVisible.length) return;
1537
+ } else {
1538
+ if ($lisVisible.filter('.selected').length === 0) return;
1539
+ }
1540
+
1541
+ $lisVisible.toggleClass('selected', status);
1542
+
1543
+ for (var i = 0; i < lisVisLen; i++) {
1544
+ var origIndex = $lisVisible[i].getAttribute('data-original-index');
1545
+ selectedOptions[selectedOptions.length] = $options.eq(origIndex)[0];
1546
+ }
1547
+
1548
+ $(selectedOptions).prop('selected', status);
1549
+
1550
+ this.render(false);
1551
+
1552
+ this.togglePlaceholder();
1553
+
1554
+ this.$element.triggerNative('change');
1555
+ },
1556
+
1557
+ selectAll: function() {
1558
+ return this.changeAll(true);
1559
+ },
1560
+
1561
+ deselectAll: function() {
1562
+ return this.changeAll(false);
1563
+ },
1564
+
1565
+ toggle: function(e) {
1566
+ e = e || window.event;
1567
+
1568
+ if (e) e.stopPropagation();
1569
+
1570
+ this.$button.trigger('click');
1571
+ },
1572
+
1573
+ keydown: function(e) {
1574
+ var $this = $(this),
1575
+ $parent = $this.is('input') ? $this.parent().parent() : $this.parent(),
1576
+ $items,
1577
+ that = $parent.data('this'),
1578
+ index,
1579
+ prevIndex,
1580
+ isActive,
1581
+ selector = ':not(.disabled, .d-none, .dropdown-header, .dropdown-divider)',
1582
+ keyCodeMap = {
1583
+ 32: ' ',
1584
+ 48: '0',
1585
+ 49: '1',
1586
+ 50: '2',
1587
+ 51: '3',
1588
+ 52: '4',
1589
+ 53: '5',
1590
+ 54: '6',
1591
+ 55: '7',
1592
+ 56: '8',
1593
+ 57: '9',
1594
+ 59: ';',
1595
+ 65: 'a',
1596
+ 66: 'b',
1597
+ 67: 'c',
1598
+ 68: 'd',
1599
+ 69: 'e',
1600
+ 70: 'f',
1601
+ 71: 'g',
1602
+ 72: 'h',
1603
+ 73: 'i',
1604
+ 74: 'j',
1605
+ 75: 'k',
1606
+ 76: 'l',
1607
+ 77: 'm',
1608
+ 78: 'n',
1609
+ 79: 'o',
1610
+ 80: 'p',
1611
+ 81: 'q',
1612
+ 82: 'r',
1613
+ 83: 's',
1614
+ 84: 't',
1615
+ 85: 'u',
1616
+ 86: 'v',
1617
+ 87: 'w',
1618
+ 88: 'x',
1619
+ 89: 'y',
1620
+ 90: 'z',
1621
+ 96: '0',
1622
+ 97: '1',
1623
+ 98: '2',
1624
+ 99: '3',
1625
+ 100: '4',
1626
+ 101: '5',
1627
+ 102: '6',
1628
+ 103: '7',
1629
+ 104: '8',
1630
+ 105: '9',
1631
+ };
1632
+
1633
+ isActive = that.$newElement.hasClass('open') || that.$newElement.hasClass('show');
1634
+
1635
+ if (!isActive && (e.keyCode >= 48 && e.keyCode <= 57 || e.keyCode >= 96 && e.keyCode <= 105 || e.keyCode >= 65 && e.keyCode <= 90)) {
1636
+ if (!that.options.container) {
1637
+ that.setSize();
1638
+ that.$menu.parent().addClass('open show');
1639
+ isActive = true;
1640
+ } else {
1641
+ that.$button.trigger('click');
1642
+ }
1643
+ that.$searchbox.focus();
1644
+ return;
1645
+ }
1646
+
1647
+ if (that.options.liveSearch) {
1648
+ if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive) {
1649
+ e.preventDefault();
1650
+ e.stopPropagation();
1651
+ that.$menuInner.click();
1652
+ that.$button.focus();
1653
+ }
1654
+ }
1655
+
1656
+ if (/(38|40)/.test(e.keyCode.toString(10))) {
1657
+ $items = that.$lis.filter(selector);
1658
+ if (!$items.length) return;
1659
+
1660
+ if (!that.options.liveSearch) {
1661
+ index = $items.index($items.filter(':focus'));
1662
+ } else {
1663
+ index = $items.index($items.filter('.active'));
1664
+ }
1665
+
1666
+ prevIndex = that.$menuInner.data('prevIndex');
1667
+
1668
+ if (e.keyCode == 38) {
1669
+ if ((that.options.liveSearch || index == prevIndex) && index != -1) index--;
1670
+ if (index < 0) index += $items.length;
1671
+ } else if (e.keyCode == 40) {
1672
+ if (that.options.liveSearch || index == prevIndex) index++;
1673
+ index = index % $items.length;
1674
+ }
1675
+
1676
+ that.$menuInner.data('prevIndex', index);
1677
+
1678
+ if (!that.options.liveSearch) {
1679
+ $items.eq(index).focus();
1680
+ } else {
1681
+ e.preventDefault();
1682
+ if (!$this.hasClass('dropdown-toggle')) {
1683
+ $items.removeClass('active').eq(index).addClass('active').children('span.dropdown-item-inner').focus();
1684
+ $this.focus();
1685
+ }
1686
+ }
1687
+
1688
+ } else if (!$this.is('input')) {
1689
+ var keyIndex = [],
1690
+ count,
1691
+ prevKey;
1692
+
1693
+ $items = that.$lis.filter(selector);
1694
+ $items.each(function(i) {
1695
+ if ($.trim($(this).children('span.dropdown-item-inner').text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) {
1696
+ keyIndex.push(i);
1697
+ }
1698
+ });
1699
+
1700
+ count = $(document).data('keycount');
1701
+ count++;
1702
+ $(document).data('keycount', count);
1703
+
1704
+ prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1);
1705
+
1706
+ if (prevKey != keyCodeMap[e.keyCode]) {
1707
+ count = 1;
1708
+ $(document).data('keycount', count);
1709
+ } else if (count >= keyIndex.length) {
1710
+ $(document).data('keycount', 0);
1711
+ if (count > keyIndex.length) count = 1;
1712
+ }
1713
+
1714
+ $items.eq(keyIndex[count - 1]).children('span.dropdown-item-inner').focus();
1715
+ }
1716
+
1717
+ // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
1718
+ if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) {
1719
+ if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault();
1720
+ if (!that.options.liveSearch) {
1721
+ var elem = $(':focus');
1722
+ elem.click();
1723
+ // Bring back focus for multiselects
1724
+ elem.focus();
1725
+ // Prevent screen from scrolling if the user hit the spacebar
1726
+ e.preventDefault();
1727
+ // Fixes spacebar selection of dropdown items in FF & IE
1728
+ $(document).data('spaceSelect', true);
1729
+ } else if (!/(32)/.test(e.keyCode.toString(10))) {
1730
+ that.$menuInner.find('a.active').click();
1731
+ $this.focus();
1732
+ }
1733
+ $(document).data('keycount', 0);
1734
+ }
1735
+
1736
+ if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) {
1737
+ that.$menu.parent().removeClass('open');
1738
+ if (that.options.container) that.$newElement.removeClass('open');
1739
+ that.$button.focus();
1740
+ }
1741
+ },
1742
+
1743
+ mobile: function() {
1744
+ this.$element.addClass('mobile-device');
1745
+ },
1746
+
1747
+ refresh: function() {
1748
+ this.$lis = null;
1749
+ this.liObj = {};
1750
+ this.reloadLi();
1751
+ this.render();
1752
+ this.checkDisabled();
1753
+ this.liHeight(true);
1754
+ this.setStyle();
1755
+ this.setWidth();
1756
+ if (this.$lis) this.$searchbox.trigger('propertychange');
1757
+
1758
+ this.$element.trigger('refreshed.bs.select');
1759
+ },
1760
+
1761
+ hide: function() {
1762
+ this.$newElement.hide();
1763
+ },
1764
+
1765
+ show: function() {
1766
+ this.$newElement.show();
1767
+ },
1768
+
1769
+ remove: function() {
1770
+ this.$newElement.remove();
1771
+ this.$element.remove();
1772
+ },
1773
+
1774
+ destroy: function() {
1775
+ this.$newElement.before(this.$element).remove();
1776
+
1777
+ if (this.$bsContainer) {
1778
+ this.$bsContainer.remove();
1779
+ } else {
1780
+ this.$menu.remove();
1781
+ }
1782
+
1783
+ this.$element.off('.bs.select').removeData('selectpicker').removeClass('bs-select-hidden selectpicker');
1784
+ },
1785
+ };
1786
+
1787
+ // SELECTPICKER PLUGIN DEFINITION
1788
+ // ==============================
1789
+ function Plugin(option) {
1790
+ // get the args of the outer function..
1791
+ var args = arguments;
1792
+ // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
1793
+ // to get lost/corrupted in android 2.3 and IE9 #715 #775
1794
+ var _option = option;
1795
+
1796
+ [].shift.apply(args);
1797
+
1798
+ var value;
1799
+ var chain = this.each(function() {
1800
+ var $this = $(this);
1801
+ if ($this.is('select')) {
1802
+ var data = $this.data('selectpicker'),
1803
+ options = typeof _option == 'object' && _option;
1804
+
1805
+ if (!data) {
1806
+ var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options);
1807
+ config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), $this.data().template, options.template);
1808
+ $this.data('selectpicker', (data = new Selectpicker(this, config)));
1809
+ } else if (options) {
1810
+ for (var i in options) {
1811
+ if (options.hasOwnProperty(i)) {
1812
+ data.options[i] = options[i];
1813
+ }
1814
+ }
1815
+ }
1816
+
1817
+ if (typeof _option == 'string') {
1818
+ if (data[_option] instanceof Function) {
1819
+ value = data[_option].apply(data, args);
1820
+ } else {
1821
+ value = data.options[_option];
1822
+ }
1823
+ }
1824
+ }
1825
+ });
1826
+
1827
+ if (typeof value !== 'undefined') {
1828
+ //noinspection JSUnusedAssignment
1829
+ return value;
1830
+ } else {
1831
+ return chain;
1832
+ }
1833
+ }
1834
+
1835
+ var old = $.fn.selectpicker;
1836
+ $.fn.selectpicker = Plugin;
1837
+ $.fn.selectpicker.Constructor = Selectpicker;
1838
+
1839
+ // SELECTPICKER NO CONFLICT
1840
+ // ========================
1841
+ $.fn.selectpicker.noConflict = function() {
1842
+ $.fn.selectpicker = old;
1843
+ return this;
1844
+ };
1845
+
1846
+ $(document).data('keycount', 0).on('keydown.bs.select', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', Selectpicker.prototype.keydown).on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', function(e) {
1847
+ e.stopPropagation();
1848
+ });
1849
+
1850
+ // SELECTPICKER DATA-API
1851
+ // =====================
1852
+ $(window).on('load.bs.select.data-api', function() {
1853
+ $('.selectpicker').each(function() {
1854
+ var $selectpicker = $(this);
1855
+ Plugin.call($selectpicker, $selectpicker.data());
1856
+ });
1857
+ });
1858
+ })(jQuery);
1859
+
1860
+ }));