jumbo-jekyll-theme 5.7.0 → 5.7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/_config.yml +42 -1
  3. data/_includes/blog/disqus_comments.html +1 -2
  4. data/_includes/blog/post_sidebar.html +3 -10
  5. data/_includes/components/breadcrumb.html +0 -3
  6. data/_includes/components/github_edit.html +21 -48
  7. data/_includes/components/head.html +2 -1
  8. data/_includes/components/schema.html +1 -43
  9. data/_includes/footer/footer.html +3 -0
  10. data/_includes/js_bundles/app.html +0 -1
  11. data/_includes/js_bundles/vendor.html +0 -1
  12. data/_includes/nav/nav.html +1 -1
  13. data/_includes/social_media_icons.html +10 -14
  14. data/_layouts/base.html +0 -1
  15. metadata +2 -39
  16. data/_data/settings.yml +0 -97
  17. data/_data/sidebar-nav.yml +0 -23
  18. data/_data/sticky-tab-bar.yml +0 -29
  19. data/_data/tags.yml +0 -11
  20. data/_includes/blog/post_tags.html +0 -9
  21. data/assets/css/main-blog.scss +0 -15
  22. data/assets/css/main-error.scss +0 -14
  23. data/assets/css/main-search.scss +0 -14
  24. data/assets/images/placeholder.png +0 -0
  25. data/assets/js/app/scroll-to-anchors.js +0 -11
  26. data/assets/js/app/sticky-tab-bar.js +0 -68
  27. data/assets/js/app/tables.js +0 -35
  28. data/assets/js/vendor/bootstrap-multiselect.js +0 -1776
  29. data/assets/js/vendor/cognito.js +0 -11
  30. data/assets/js/vendor/disqus-loader.js +0 -87
  31. data/assets/js/vendor/fess-ss.min.js +0 -24
  32. data/assets/js/vendor/jquery.doubleScroll.js +0 -128
  33. data/assets/js/vendor/jquery.rss.js +0 -333
  34. data/assets/js/vendor/jquery.slim.js +0 -8842
  35. data/assets/js/vendor/jquery.validate.js +0 -1601
  36. data/assets/js/vendor/loadCSS.js +0 -35
  37. data/assets/js/vendor/picturefill.js +0 -1471
  38. data/assets/js/vendor/shuffle.js +0 -2004
@@ -1,23 +0,0 @@
1
- pages:
2
- -
3
- list:
4
- -
5
- title: "Container Left Sidebar"
6
- url: /jekyll/layouts/container-left-sidebar/
7
- -
8
- title: "Container Right Sidebar"
9
- url: "/jekyll/layouts/container-right-sidebar/"
10
- -
11
- title: "Container Breadcrumb Left Sidebar"
12
- url: "/jekyll/layouts/container-breadcrumb-left-sidebar/"
13
- -
14
- title: "Container Breadcrumb Right Sidebar"
15
- url: "/jekyll/layouts/container-breadcrumb-right-sidebar/"
16
- # custom-include: custom
17
- # Custom includes can be used using the above setting. Simply add the name of the
18
- # jekyll _include file (without .html exetension) to the above setting and that will be used instead.
19
- urls: [
20
- /jekyll/layouts/container-breadcrumb-left-sidebar/,
21
- /jekyll/layouts/container-breadcrumb-right-sidebar/,
22
- /jekyll/layouts/container-left-sidebar/,
23
- /jekyll/layouts/container-right-sidebar/]
@@ -1,29 +0,0 @@
1
- pages:
2
- -
3
- list:
4
- -
5
- title: "Home"
6
- url: /
7
- -
8
- title: "About"
9
- url: "/about/"
10
- -
11
- title: "FAQ"
12
- url: "/faq/"
13
- -
14
- title: "Jekyll"
15
- url: "/jekyll/"
16
-
17
- urls: [
18
- /,
19
- /about/,
20
- /faq/,
21
- /jekyll/]
22
- -
23
- list:
24
- -
25
- title: "Container Breadcrumb"
26
- url: /jekyll/layouts/container-breadcrumb/
27
-
28
- urls: [
29
- /jekyll/layouts/container-breadcrumb/]
@@ -1,11 +0,0 @@
1
- items:
2
- - name: Productivity
3
- slug: productivity
4
- - name: News
5
- slug: news
6
- - name: Blog
7
- slug: blog
8
- - name: Case Study
9
- slug: case-study
10
- - name: Update
11
- slug: update
@@ -1,9 +0,0 @@
1
- {% if site.data.settings.blog.tags_enabled %}
2
- {% if post.tags %}
3
- <h3>Tags</h3>
4
- {% assign tags = post.tags %}
5
- {% for tag in tags %}
6
- <a class="btn btn-blog btn-xs post_tag" href="/blog/tag#{{tag | slugify }}">{{tag}}</a>
7
- {% endfor %}
8
- {% endif %}
9
- {% endif %}
@@ -1,15 +0,0 @@
1
- ---
2
- ---
3
- @charset "UTF-8";
4
- //Bootstrap Overrides
5
- @import "bootstrap/functions";
6
- @import "bootstrap/variables";
7
- @import "bootstrap/mixins";
8
-
9
- @import "app/overrides";
10
- //Boostrap Includes
11
- @import 'bootstrap/bootstrap';
12
- // Linaro Jekyll Theme Includes
13
- @import 'core';
14
- // Additional Core Includes
15
- @import 'blog';
@@ -1,14 +0,0 @@
1
- ---
2
- ---
3
- @charset "UTF-8";
4
- @import "bootstrap/functions";
5
- @import "bootstrap/variables";
6
- @import "bootstrap/mixins";
7
- // App Overrides - Sass variables
8
- @import "app/overrides";
9
- //Boostrap Includes
10
- @import 'bootstrap/bootstrap';
11
- // Core Theme
12
- @import 'core';
13
- //Additional Core includes
14
- @import "core/error";
@@ -1,14 +0,0 @@
1
- ---
2
- ---
3
- @charset "UTF-8";
4
- @import "bootstrap/functions";
5
- @import "bootstrap/variables";
6
- @import "bootstrap/mixins";
7
- //Bootstrap Overrides
8
- @import "app/overrides";
9
- //Boostrap Includes
10
- @import 'bootstrap/bootstrap';
11
- // Linaro Jekyll Theme Includes
12
- @import "core";
13
- // App Includes
14
- @import "app/search";
@@ -1,11 +0,0 @@
1
- // Animated scroll to anchors and offset
2
- var $root = $("html, body");
3
- $('#content-container a[href^="#"]').click(function() {
4
- $root.animate(
5
- {
6
- scrollTop: $($.attr(this, "href")).offset().top - 200
7
- },
8
- 500
9
- );
10
- return false;
11
- });
@@ -1,68 +0,0 @@
1
- $(document).ready(function() {
2
- // Check to see if the tabbed nav bar is in use.
3
- if ($("#tabbed-nav-bar").length > 0) {
4
- // Set the sub nav text
5
- var text = $("#tabbed-nav-bar ul.nav-tabs li.active a").text();
6
- $("#sub-navigation-header").text(text);
7
- console.log(text);
8
- // Menu selector
9
- var menu = $("#tabbed-nav-bar");
10
- // Get sub nav offset from the page top
11
- var origOffsetY = menu.offset().top;
12
- if ($("#universal-nav").length > 0) {
13
- origOffsetY = origOffsetY - 20;
14
- }
15
- // Instantiate Bootstrap 3 Affix plugin
16
- $("#tabbed-nav-bar").affix({
17
- offset: {
18
- top: origOffsetY
19
- }
20
- });
21
- // Event listeners
22
- $("#tabbed-nav-bar").on("affixed.bs.affix", function() {
23
- affixed();
24
- });
25
- $("#tabbed-nav-bar").on("affixed-top.bs.affix ", function() {
26
- affixTop();
27
- });
28
- function scroll() {
29
- if ($("#tabbed-nav-bar.affix-top").length > 0) {
30
- affixTop();
31
- }
32
- if ($("#tabbed-nav-bar.affix").length > 0) {
33
- affixed();
34
- }
35
- }
36
- function affixTop() {
37
- $("#tabbed-nav-bar").addClass("non-sticky-nav");
38
- $("#tabbed-nav-bar").removeClass("sticky-nav");
39
- $("nav#main-navigation").show();
40
- if ($(window).width() < 1000) {
41
- $("#tabbed-nav-bar ul.nav-tabs").addClass("nav-stacked");
42
- $("#sub-navigation-header").show();
43
- } else {
44
- $("#tabbed-nav-bar ul.nav-tabs").removeClass("nav-stacked");
45
- $("#sub-navigation-header").hide();
46
- }
47
- }
48
- function affixed() {
49
- // Set thge sticky-nav clas
50
- $("#tabbed-nav-bar").removeClass("non-sticky-nav");
51
- $("#tabbed-nav-bar").addClass("sticky-nav");
52
- // Hide the main navigation bar
53
- $("nav#main-navigation").hide();
54
- if ($(window).width() < 768) {
55
- $("#tabbed-nav-bar ul.nav-tabs").addClass("nav-stacked");
56
- $("#sub-navigation-header").show();
57
- } else {
58
- $("#tabbed-nav-bar ul.nav-tabs").removeClass("nav-stacked");
59
- $("#sub-navigation-header").hide();
60
- }
61
- }
62
- scroll();
63
- $(window).scroll(function() {
64
- scroll();
65
- });
66
- $(window).resize(scroll);
67
- }
68
- });
@@ -1,35 +0,0 @@
1
- var numShown = 5; // Initial rows shown & index
2
- var numMore = 5; // Increment
3
-
4
- var $table = $('table.hidden_rows').find('tbody'); // tbody containing all the rows
5
- var numRows = $table.find('tr').length; // Total # rows
6
-
7
- $(function () {
8
- // Hide rows and add clickable div
9
- $table.find('tr:gt(' + (numShown - 1) + ')').hide().end()
10
- .after('<tbody id="more"><tr><td colspan="' +
11
- $table.find('tr:first td').length + '"><div>Show <span>' +
12
- numMore + '</span> More</div</tbody></td></tr>');
13
-
14
- $('#more').click(function() {
15
- numShown = numShown + numMore;
16
- // no more "show more" if done
17
- if (numShown >= numRows) {
18
- $('#more').remove();
19
- }
20
- // change rows remaining if less than increment
21
- if (numRows - numShown < numMore) {
22
- $('#more span').html(numRows - numShown);
23
- }
24
- $table.find('tr:lt(' + numShown + ')').show();
25
- });
26
- $('#all').click(function() {
27
- numShown = numRows;
28
- // no more "show more" if done
29
- if (numShown >= numRows) {
30
- $('#all').remove();
31
- }
32
- $table.find('tr:lt(' + numShown + ')').show();
33
- });
34
-
35
- });
@@ -1,1776 +0,0 @@
1
- /**
2
- * Bootstrap Multiselect (http://davidstutz.de/bootstrap-multiselect/)
3
- *
4
- * Apache License, Version 2.0:
5
- * Copyright (c) 2012 - 2018 David Stutz
6
- *
7
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
- * use this file except in compliance with the License. You may obtain a
9
- * copy of the License at http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
- * License for the specific language governing permissions and limitations
15
- * under the License.
16
- *
17
- * BSD 3-Clause License:
18
- * Copyright (c) 2012 - 2018 David Stutz
19
- * All rights reserved.
20
- *
21
- * Redistribution and use in source and binary forms, with or without
22
- * modification, are permitted provided that the following conditions are met:
23
- * - Redistributions of source code must retain the above copyright notice,
24
- * this list of conditions and the following disclaimer.
25
- * - Redistributions in binary form must reproduce the above copyright notice,
26
- * this list of conditions and the following disclaimer in the documentation
27
- * and/or other materials provided with the distribution.
28
- * - Neither the name of David Stutz nor the names of its contributors may be
29
- * used to endorse or promote products derived from this software without
30
- * specific prior written permission.
31
- *
32
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
34
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
36
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
38
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
39
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
40
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
41
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
- */
44
- (function (root, factory) {
45
- // check to see if 'knockout' AMD module is specified if using requirejs
46
- if (typeof define === 'function' && define.amd &&
47
- typeof require === 'function' && typeof require.specified === 'function' && require.specified('knockout')) {
48
-
49
- // AMD. Register as an anonymous module.
50
- define(['jquery', 'knockout'], factory);
51
- } else {
52
- // Browser globals
53
- factory(root.jQuery, root.ko);
54
- }
55
- })(this, function ($, ko) {
56
- "use strict";// jshint ;_;
57
-
58
- if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
59
- ko.bindingHandlers.multiselect = {
60
- after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],
61
-
62
- init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
63
- var $element = $(element);
64
- var config = ko.toJS(valueAccessor());
65
-
66
- $element.multiselect(config);
67
-
68
- if (allBindings.has('options')) {
69
- var options = allBindings.get('options');
70
- if (ko.isObservable(options)) {
71
- ko.computed({
72
- read: function() {
73
- options();
74
- setTimeout(function() {
75
- var ms = $element.data('multiselect');
76
- if (ms)
77
- ms.updateOriginalOptions();//Not sure how beneficial this is.
78
- $element.multiselect('rebuild');
79
- }, 1);
80
- },
81
- disposeWhenNodeIsRemoved: element
82
- });
83
- }
84
- }
85
-
86
- //value and selectedOptions are two-way, so these will be triggered even by our own actions.
87
- //It needs some way to tell if they are triggered because of us or because of outside change.
88
- //It doesn't loop but it's a waste of processing.
89
- if (allBindings.has('value')) {
90
- var value = allBindings.get('value');
91
- if (ko.isObservable(value)) {
92
- ko.computed({
93
- read: function() {
94
- value();
95
- setTimeout(function() {
96
- $element.multiselect('refresh');
97
- }, 1);
98
- },
99
- disposeWhenNodeIsRemoved: element
100
- }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
101
- }
102
- }
103
-
104
- //Switched from arrayChange subscription to general subscription using 'refresh'.
105
- //Not sure performance is any better using 'select' and 'deselect'.
106
- if (allBindings.has('selectedOptions')) {
107
- var selectedOptions = allBindings.get('selectedOptions');
108
- if (ko.isObservable(selectedOptions)) {
109
- ko.computed({
110
- read: function() {
111
- selectedOptions();
112
- setTimeout(function() {
113
- $element.multiselect('refresh');
114
- }, 1);
115
- },
116
- disposeWhenNodeIsRemoved: element
117
- }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
118
- }
119
- }
120
-
121
- var setEnabled = function (enable) {
122
- setTimeout(function () {
123
- if (enable)
124
- $element.multiselect('enable');
125
- else
126
- $element.multiselect('disable');
127
- });
128
- };
129
-
130
- if (allBindings.has('enable')) {
131
- var enable = allBindings.get('enable');
132
- if (ko.isObservable(enable)) {
133
- ko.computed({
134
- read: function () {
135
- setEnabled(enable());
136
- },
137
- disposeWhenNodeIsRemoved: element
138
- }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
139
- } else {
140
- setEnabled(enable);
141
- }
142
- }
143
-
144
- if (allBindings.has('disable')) {
145
- var disable = allBindings.get('disable');
146
- if (ko.isObservable(disable)) {
147
- ko.computed({
148
- read: function () {
149
- setEnabled(!disable());
150
- },
151
- disposeWhenNodeIsRemoved: element
152
- }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
153
- } else {
154
- setEnabled(!disable);
155
- }
156
- }
157
-
158
- ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
159
- $element.multiselect('destroy');
160
- });
161
- },
162
-
163
- update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
164
- var $element = $(element);
165
- var config = ko.toJS(valueAccessor());
166
-
167
- $element.multiselect('setOptions', config);
168
- $element.multiselect('rebuild');
169
- }
170
- };
171
- }
172
-
173
- function forEach(array, callback) {
174
- for (var index = 0; index < array.length; ++index) {
175
- callback(array[index], index);
176
- }
177
- }
178
-
179
- /**
180
- * Constructor to create a new multiselect using the given select.
181
- *
182
- * @param {jQuery} select
183
- * @param {Object} options
184
- * @returns {Multiselect}
185
- */
186
- function Multiselect(select, options) {
187
-
188
- this.$select = $(select);
189
- this.options = this.mergeOptions($.extend({}, options, this.$select.data()));
190
-
191
- // Placeholder via data attributes
192
- if (this.$select.attr("data-placeholder")) {
193
- this.options.nonSelectedText = this.$select.data("placeholder");
194
- }
195
-
196
- // Initialization.
197
- // We have to clone to create a new reference.
198
- this.originalOptions = this.$select.clone()[0].options;
199
- this.query = '';
200
- this.searchTimeout = null;
201
- this.lastToggledInput = null;
202
-
203
- this.options.multiple = this.$select.attr('multiple') === "multiple";
204
- this.options.onChange = $.proxy(this.options.onChange, this);
205
- this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);
206
- this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);
207
- this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
208
- this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
209
- this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
210
- this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
211
- this.options.onInitialized = $.proxy(this.options.onInitialized, this);
212
- this.options.onFiltering = $.proxy(this.options.onFiltering, this);
213
-
214
- // Build select all if enabled.
215
- this.buildContainer();
216
- this.buildButton();
217
- this.buildDropdown();
218
- this.buildReset();
219
- this.buildSelectAll();
220
- this.buildDropdownOptions();
221
- this.buildFilter();
222
-
223
- this.updateButtonText();
224
- this.updateSelectAll(true);
225
-
226
- if (this.options.enableClickableOptGroups && this.options.multiple) {
227
- this.updateOptGroups();
228
- }
229
-
230
- this.options.wasDisabled = this.$select.prop('disabled');
231
- if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
232
- this.disable();
233
- }
234
-
235
- this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container);
236
- this.options.onInitialized(this.$select, this.$container);
237
- }
238
-
239
- Multiselect.prototype = {
240
-
241
- defaults: {
242
- /**
243
- * Default text function will either print 'None selected' in case no
244
- * option is selected or a list of the selected options up to a length
245
- * of 3 selected options.
246
- *
247
- * @param {jQuery} options
248
- * @param {jQuery} select
249
- * @returns {String}
250
- */
251
- buttonText: function(options, select) {
252
- if (this.disabledText.length > 0
253
- && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) {
254
-
255
- return this.disabledText;
256
- }
257
- else if (options.length === 0) {
258
- return this.nonSelectedText;
259
- }
260
- else if (this.allSelectedText
261
- && options.length === $('option', $(select)).length
262
- && $('option', $(select)).length !== 1
263
- && this.multiple) {
264
-
265
- if (this.selectAllNumber) {
266
- return this.allSelectedText + ' (' + options.length + ')';
267
- }
268
- else {
269
- return this.allSelectedText;
270
- }
271
- }
272
- else if (this.numberDisplayed != 0 && options.length > this.numberDisplayed) {
273
- return options.length + ' ' + this.nSelectedText;
274
- }
275
- else {
276
- var selected = '';
277
- var delimiter = this.delimiterText;
278
-
279
- options.each(function() {
280
- var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
281
- selected += label + delimiter;
282
- });
283
-
284
- return selected.substr(0, selected.length - this.delimiterText.length);
285
- }
286
- },
287
- /**
288
- * Updates the title of the button similar to the buttonText function.
289
- *
290
- * @param {jQuery} options
291
- * @param {jQuery} select
292
- * @returns {@exp;selected@call;substr}
293
- */
294
- buttonTitle: function(options, select) {
295
- if (options.length === 0) {
296
- return this.nonSelectedText;
297
- }
298
- else {
299
- var selected = '';
300
- var delimiter = this.delimiterText;
301
-
302
- options.each(function () {
303
- var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
304
- selected += label + delimiter;
305
- });
306
- return selected.substr(0, selected.length - this.delimiterText.length);
307
- }
308
- },
309
- checkboxName: function(option) {
310
- return false; // no checkbox name
311
- },
312
- /**
313
- * Create a label.
314
- *
315
- * @param {jQuery} element
316
- * @returns {String}
317
- */
318
- optionLabel: function(element){
319
- return $(element).attr('label') || $(element).text();
320
- },
321
- /**
322
- * Create a class.
323
- *
324
- * @param {jQuery} element
325
- * @returns {String}
326
- */
327
- optionClass: function(element) {
328
- return $(element).attr('class') || '';
329
- },
330
- /**
331
- * Triggered on change of the multiselect.
332
- *
333
- * Not triggered when selecting/deselecting options manually.
334
- *
335
- * @param {jQuery} option
336
- * @param {Boolean} checked
337
- */
338
- onChange : function(option, checked) {
339
-
340
- },
341
- /**
342
- * Triggered when the dropdown is shown.
343
- *
344
- * @param {jQuery} event
345
- */
346
- onDropdownShow: function(event) {
347
-
348
- },
349
- /**
350
- * Triggered when the dropdown is hidden.
351
- *
352
- * @param {jQuery} event
353
- */
354
- onDropdownHide: function(event) {
355
-
356
- },
357
- /**
358
- * Triggered after the dropdown is shown.
359
- *
360
- * @param {jQuery} event
361
- */
362
- onDropdownShown: function(event) {
363
-
364
- },
365
- /**
366
- * Triggered after the dropdown is hidden.
367
- *
368
- * @param {jQuery} event
369
- */
370
- onDropdownHidden: function(event) {
371
-
372
- },
373
- /**
374
- * Triggered on select all.
375
- */
376
- onSelectAll: function() {
377
-
378
- },
379
- /**
380
- * Triggered on deselect all.
381
- */
382
- onDeselectAll: function() {
383
-
384
- },
385
- /**
386
- * Triggered after initializing.
387
- *
388
- * @param {jQuery} $select
389
- * @param {jQuery} $container
390
- */
391
- onInitialized: function($select, $container) {
392
-
393
- },
394
- /**
395
- * Triggered on filtering.
396
- *
397
- * @param {jQuery} $filter
398
- */
399
- onFiltering: function($filter) {
400
-
401
- },
402
- enableHTML: false,
403
- buttonClass: 'btn btn-default',
404
- inheritClass: false,
405
- buttonWidth: 'auto',
406
- buttonContainer: '<div class="btn-group" />',
407
- dropRight: false,
408
- dropUp: false,
409
- selectedClass: 'active',
410
- // Maximum height of the dropdown menu.
411
- // If maximum height is exceeded a scrollbar will be displayed.
412
- maxHeight: false,
413
- includeSelectAllOption: false,
414
- includeSelectAllIfMoreThan: 0,
415
- selectAllText: ' Select all',
416
- selectAllValue: 'multiselect-all',
417
- selectAllName: false,
418
- selectAllNumber: true,
419
- selectAllJustVisible: true,
420
- enableFiltering: false,
421
- enableCaseInsensitiveFiltering: false,
422
- enableFullValueFiltering: false,
423
- enableClickableOptGroups: false,
424
- enableCollapsibleOptGroups: false,
425
- collapseOptGroupsByDefault: false,
426
- filterPlaceholder: 'Search',
427
- // possible options: 'text', 'value', 'both'
428
- filterBehavior: 'text',
429
- includeFilterClearBtn: true,
430
- preventInputChangeEvent: false,
431
- nonSelectedText: 'None selected',
432
- nSelectedText: 'selected',
433
- allSelectedText: 'All selected',
434
- numberDisplayed: 3,
435
- disableIfEmpty: false,
436
- disabledText: '',
437
- delimiterText: ', ',
438
- includeResetOption: false,
439
- includeResetDivider: false,
440
- resetText: 'Reset',
441
- templates: {
442
- button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',
443
- ul: '<ul class="multiselect-container dropdown-menu"></ul>',
444
- filter: '<li class="multiselect-item multiselect-filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text" /></div></li>',
445
- filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>',
446
- li: '<li><a tabindex="0"><label></label></a></li>',
447
- divider: '<li class="multiselect-item divider"></li>',
448
- liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>',
449
- resetButton: '<li class="multiselect-reset text-center"><div class="input-group"><a class="btn btn-default btn-block"></a></div></li>'
450
- }
451
- },
452
-
453
- constructor: Multiselect,
454
-
455
- /**
456
- * Builds the container of the multiselect.
457
- */
458
- buildContainer: function() {
459
- this.$container = $(this.options.buttonContainer);
460
- this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
461
- this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
462
- this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
463
- this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
464
- },
465
-
466
- /**
467
- * Builds the button of the multiselect.
468
- */
469
- buildButton: function() {
470
- this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
471
- if (this.$select.attr('class') && this.options.inheritClass) {
472
- this.$button.addClass(this.$select.attr('class'));
473
- }
474
- // Adopt active state.
475
- if (this.$select.prop('disabled')) {
476
- this.disable();
477
- }
478
- else {
479
- this.enable();
480
- }
481
-
482
- // Manually add button width if set.
483
- if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
484
- this.$button.css({
485
- 'width' : '100%', //this.options.buttonWidth,
486
- 'overflow' : 'hidden',
487
- 'text-overflow' : 'ellipsis'
488
- });
489
- this.$container.css({
490
- 'width': this.options.buttonWidth
491
- });
492
- }
493
-
494
- // Keep the tab index from the select.
495
- var tabindex = this.$select.attr('tabindex');
496
- if (tabindex) {
497
- this.$button.attr('tabindex', tabindex);
498
- }
499
-
500
- this.$container.prepend(this.$button);
501
- },
502
-
503
- /**
504
- * Builds the ul representing the dropdown menu.
505
- */
506
- buildDropdown: function() {
507
-
508
- // Build ul.
509
- this.$ul = $(this.options.templates.ul);
510
-
511
- if (this.options.dropRight) {
512
- this.$ul.addClass('pull-right');
513
- }
514
-
515
- // Set max height of dropdown menu to activate auto scrollbar.
516
- if (this.options.maxHeight) {
517
- // TODO: Add a class for this option to move the css declarations.
518
- this.$ul.css({
519
- 'max-height': this.options.maxHeight + 'px',
520
- 'overflow-y': 'auto',
521
- 'overflow-x': 'hidden'
522
- });
523
- }
524
-
525
- if (this.options.dropUp) {
526
-
527
- var height = Math.min(this.options.maxHeight, $('option[data-role!="divider"]', this.$select).length*26 + $('option[data-role="divider"]', this.$select).length*19 + (this.options.includeSelectAllOption ? 26 : 0) + (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering ? 44 : 0));
528
- var moveCalc = height + 34;
529
-
530
- this.$ul.css({
531
- 'max-height': height + 'px',
532
- 'overflow-y': 'auto',
533
- 'overflow-x': 'hidden',
534
- 'margin-top': "-" + moveCalc + 'px'
535
- });
536
- }
537
-
538
- this.$container.append(this.$ul);
539
- },
540
-
541
- /**
542
- * Build the dropdown options and binds all necessary events.
543
- *
544
- * Uses createDivider and createOptionValue to create the necessary options.
545
- */
546
- buildDropdownOptions: function() {
547
-
548
- this.$select.children().each($.proxy(function(index, element) {
549
-
550
- var $element = $(element);
551
- // Support optgroups and options without a group simultaneously.
552
- var tag = $element.prop('tagName')
553
- .toLowerCase();
554
-
555
- if ($element.prop('value') === this.options.selectAllValue) {
556
- return;
557
- }
558
-
559
- if (tag === 'optgroup') {
560
- this.createOptgroup(element);
561
- }
562
- else if (tag === 'option') {
563
-
564
- if ($element.data('role') === 'divider') {
565
- this.createDivider();
566
- }
567
- else {
568
- this.createOptionValue(element);
569
- }
570
-
571
- }
572
-
573
- // Other illegal tags will be ignored.
574
- }, this));
575
-
576
- // Bind the change event on the dropdown elements.
577
- $(this.$ul).off('change', 'li:not(.multiselect-group) input[type="checkbox"], li:not(.multiselect-group) input[type="radio"]');
578
- $(this.$ul).on('change', 'li:not(.multiselect-group) input[type="checkbox"], li:not(.multiselect-group) input[type="radio"]', $.proxy(function(event) {
579
- var $target = $(event.target);
580
-
581
- var checked = $target.prop('checked') || false;
582
- var isSelectAllOption = $target.val() === this.options.selectAllValue;
583
-
584
- // Apply or unapply the configured selected class.
585
- if (this.options.selectedClass) {
586
- if (checked) {
587
- $target.closest('li')
588
- .addClass(this.options.selectedClass);
589
- }
590
- else {
591
- $target.closest('li')
592
- .removeClass(this.options.selectedClass);
593
- }
594
- }
595
-
596
- // Get the corresponding option.
597
- var value = $target.val();
598
- var $option = this.getOptionByValue(value);
599
-
600
- var $optionsNotThis = $('option', this.$select).not($option);
601
- var $checkboxesNotThis = $('input', this.$container).not($target);
602
-
603
- if (isSelectAllOption) {
604
-
605
- if (checked) {
606
- this.selectAll(this.options.selectAllJustVisible, true);
607
- }
608
- else {
609
- this.deselectAll(this.options.selectAllJustVisible, true);
610
- }
611
- }
612
- else {
613
- if (checked) {
614
- $option.prop('selected', true);
615
-
616
- if (this.options.multiple) {
617
- // Simply select additional option.
618
- $option.prop('selected', true);
619
- }
620
- else {
621
- // Unselect all other options and corresponding checkboxes.
622
- if (this.options.selectedClass) {
623
- $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);
624
- }
625
-
626
- $($checkboxesNotThis).prop('checked', false);
627
- $optionsNotThis.prop('selected', false);
628
-
629
- // It's a single selection, so close.
630
- this.$button.click();
631
- }
632
-
633
- if (this.options.selectedClass === "active") {
634
- $optionsNotThis.closest("a").css("outline", "");
635
- }
636
- }
637
- else {
638
- // Unselect option.
639
- $option.prop('selected', false);
640
- }
641
-
642
- // To prevent select all from firing onChange: #575
643
- this.options.onChange($option, checked);
644
-
645
- // Do not update select all or optgroups on select all change!
646
- this.updateSelectAll();
647
-
648
- if (this.options.enableClickableOptGroups && this.options.multiple) {
649
- this.updateOptGroups();
650
- }
651
- }
652
-
653
- this.$select.change();
654
- this.updateButtonText();
655
-
656
- if(this.options.preventInputChangeEvent) {
657
- return false;
658
- }
659
- }, this));
660
-
661
- $('li a', this.$ul).on('mousedown', function(e) {
662
- if (e.shiftKey) {
663
- // Prevent selecting text by Shift+click
664
- return false;
665
- }
666
- });
667
-
668
- $(this.$ul).on('touchstart click', 'li a', $.proxy(function(event) {
669
- event.stopPropagation();
670
-
671
- var $target = $(event.target);
672
-
673
- if (event.shiftKey && this.options.multiple) {
674
- if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
675
- event.preventDefault();
676
- $target = $target.find("input");
677
- $target.prop("checked", !$target.prop("checked"));
678
- }
679
- var checked = $target.prop('checked') || false;
680
-
681
- if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
682
- var from = this.$ul.find("li:visible").index($target.parents("li"));
683
- var to = this.$ul.find("li:visible").index(this.lastToggledInput.parents("li"));
684
-
685
- if (from > to) { // Swap the indices
686
- var tmp = to;
687
- to = from;
688
- from = tmp;
689
- }
690
-
691
- // Make sure we grab all elements since slice excludes the last index
692
- ++to;
693
-
694
- // Change the checkboxes and underlying options
695
- var range = this.$ul.find("li").not(".multiselect-filter-hidden").slice(from, to).find("input");
696
-
697
- range.prop('checked', checked);
698
-
699
- if (this.options.selectedClass) {
700
- range.closest('li')
701
- .toggleClass(this.options.selectedClass, checked);
702
- }
703
-
704
- for (var i = 0, j = range.length; i < j; i++) {
705
- var $checkbox = $(range[i]);
706
-
707
- var $option = this.getOptionByValue($checkbox.val());
708
-
709
- $option.prop('selected', checked);
710
- }
711
- }
712
-
713
- // Trigger the select "change" event
714
- $target.trigger("change");
715
- }
716
-
717
- // Remembers last clicked option
718
- if($target.is("input") && !$target.closest("li").is(".multiselect-item")){
719
- this.lastToggledInput = $target;
720
- }
721
-
722
- $target.blur();
723
- }, this));
724
-
725
- // Keyboard support.
726
- this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) {
727
- if ($('input[type="text"]', this.$container).is(':focus')) {
728
- return;
729
- }
730
-
731
- if (event.keyCode === 9 && this.$container.hasClass('open')) {
732
- this.$button.click();
733
- }
734
- else {
735
- var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");
736
-
737
- if (!$items.length) {
738
- return;
739
- }
740
-
741
- var index = $items.index($items.filter(':focus'));
742
-
743
- // Navigation up.
744
- if (event.keyCode === 38 && index > 0) {
745
- index--;
746
- }
747
- // Navigate down.
748
- else if (event.keyCode === 40 && index < $items.length - 1) {
749
- index++;
750
- }
751
- else if (!~index) {
752
- index = 0;
753
- }
754
-
755
- var $current = $items.eq(index);
756
- $current.focus();
757
-
758
- if (event.keyCode === 32 || event.keyCode === 13) {
759
- var $checkbox = $current.find('input');
760
-
761
- $checkbox.prop("checked", !$checkbox.prop("checked"));
762
- $checkbox.change();
763
- }
764
-
765
- event.stopPropagation();
766
- event.preventDefault();
767
- }
768
- }, this));
769
-
770
- if (this.options.enableClickableOptGroups && this.options.multiple) {
771
- $("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) {
772
- event.stopPropagation();
773
-
774
- var $target = $(event.target);
775
- var checked = $target.prop('checked') || false;
776
-
777
- var $li = $(event.target).closest('li');
778
- var $group = $li.nextUntil("li.multiselect-group")
779
- .not('.multiselect-filter-hidden')
780
- .not('.disabled');
781
-
782
- var $inputs = $group.find("input");
783
-
784
- var values = [];
785
- var $options = [];
786
-
787
- if (this.options.selectedClass) {
788
- if (checked) {
789
- $li.addClass(this.options.selectedClass);
790
- }
791
- else {
792
- $li.removeClass(this.options.selectedClass);
793
- }
794
- }
795
-
796
- $.each($inputs, $.proxy(function(index, input) {
797
- var value = $(input).val();
798
- var $option = this.getOptionByValue(value);
799
-
800
- if (checked) {
801
- $(input).prop('checked', true);
802
- $(input).closest('li')
803
- .addClass(this.options.selectedClass);
804
-
805
- $option.prop('selected', true);
806
- }
807
- else {
808
- $(input).prop('checked', false);
809
- $(input).closest('li')
810
- .removeClass(this.options.selectedClass);
811
-
812
- $option.prop('selected', false);
813
- }
814
-
815
- $options.push(this.getOptionByValue(value));
816
- }, this))
817
-
818
- // Cannot use select or deselect here because it would call updateOptGroups again.
819
-
820
- this.options.onChange($options, checked);
821
-
822
- this.$select.change();
823
- this.updateButtonText();
824
- this.updateSelectAll();
825
- }, this));
826
- }
827
-
828
- if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
829
- $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) {
830
- var $li = $(event.target).closest('li');
831
- var $inputs = $li.nextUntil("li.multiselect-group")
832
- .not('.multiselect-filter-hidden');
833
-
834
- var visible = true;
835
- $inputs.each(function() {
836
- visible = visible && !$(this).hasClass('multiselect-collapsible-hidden');
837
- });
838
-
839
- if (visible) {
840
- $inputs.hide()
841
- .addClass('multiselect-collapsible-hidden');
842
- }
843
- else {
844
- $inputs.show()
845
- .removeClass('multiselect-collapsible-hidden');
846
- }
847
- }, this));
848
-
849
- $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea');
850
- $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px');
851
- $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px');
852
- }
853
- },
854
-
855
- /**
856
- * Create an option using the given select option.
857
- *
858
- * @param {jQuery} element
859
- */
860
- createOptionValue: function(element) {
861
- var $element = $(element);
862
- if ($element.is(':selected')) {
863
- $element.prop('selected', true);
864
- }
865
-
866
- // Support the label attribute on options.
867
- var label = this.options.optionLabel(element);
868
- var classes = this.options.optionClass(element);
869
- var value = $element.val();
870
- var inputType = this.options.multiple ? "checkbox" : "radio";
871
-
872
- var $li = $(this.options.templates.li);
873
- var $label = $('label', $li);
874
- $label.addClass(inputType);
875
- $label.attr("title", label);
876
- $li.addClass(classes);
877
-
878
- // Hide all children items when collapseOptGroupsByDefault is true
879
- if (this.options.collapseOptGroupsByDefault && $(element).parent().prop("tagName").toLowerCase() === "optgroup") {
880
- $li.addClass("multiselect-collapsible-hidden");
881
- $li.hide();
882
- }
883
-
884
- if (this.options.enableHTML) {
885
- $label.html(" " + label);
886
- }
887
- else {
888
- $label.text(" " + label);
889
- }
890
-
891
- var $checkbox = $('<input/>').attr('type', inputType);
892
-
893
- var name = this.options.checkboxName($element);
894
- if (name) {
895
- $checkbox.attr('name', name);
896
- }
897
-
898
- $label.prepend($checkbox);
899
-
900
- var selected = $element.prop('selected') || false;
901
- $checkbox.val(value);
902
-
903
- if (value === this.options.selectAllValue) {
904
- $li.addClass("multiselect-item multiselect-all");
905
- $checkbox.parent().parent()
906
- .addClass('multiselect-all');
907
- }
908
-
909
- $label.attr('title', $element.attr('title'));
910
-
911
- this.$ul.append($li);
912
-
913
- if ($element.is(':disabled')) {
914
- $checkbox.attr('disabled', 'disabled')
915
- .prop('disabled', true)
916
- .closest('a')
917
- .attr("tabindex", "-1")
918
- .closest('li')
919
- .addClass('disabled');
920
- }
921
-
922
- $checkbox.prop('checked', selected);
923
-
924
- if (selected && this.options.selectedClass) {
925
- $checkbox.closest('li')
926
- .addClass(this.options.selectedClass);
927
- }
928
- },
929
-
930
- /**
931
- * Creates a divider using the given select option.
932
- *
933
- * @param {jQuery} element
934
- */
935
- createDivider: function(element) {
936
- var $divider = $(this.options.templates.divider);
937
- this.$ul.append($divider);
938
- },
939
-
940
- /**
941
- * Creates an optgroup.
942
- *
943
- * @param {jQuery} group
944
- */
945
- createOptgroup: function(group) {
946
- var label = $(group).attr("label");
947
- var value = $(group).attr("value");
948
- var $li = $('<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><label><b></b></label></a></li>');
949
-
950
- var classes = this.options.optionClass(group);
951
- $li.addClass(classes);
952
-
953
- if (this.options.enableHTML) {
954
- $('label b', $li).html(" " + label);
955
- }
956
- else {
957
- $('label b', $li).text(" " + label);
958
- }
959
-
960
- if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
961
- $('a', $li).append('<span class="caret-container"><b class="caret"></b></span>');
962
- }
963
-
964
- if (this.options.enableClickableOptGroups && this.options.multiple) {
965
- $('a label', $li).prepend('<input type="checkbox" value="' + value + '"/>');
966
- }
967
-
968
- if ($(group).is(':disabled')) {
969
- $li.addClass('disabled');
970
- }
971
-
972
- this.$ul.append($li);
973
-
974
- $("option", group).each($.proxy(function($, group) {
975
- this.createOptionValue(group);
976
- }, this))
977
- },
978
-
979
- /**
980
- * Build the reset.
981
- *
982
- */
983
- buildReset: function() {
984
- if (this.options.includeResetOption) {
985
-
986
- // Check whether to add a divider after the reset.
987
- if (this.options.includeResetDivider) {
988
- this.$ul.prepend($(this.options.templates.divider));
989
- }
990
-
991
- var $resetButton = $(this.options.templates.resetButton);
992
-
993
- if (this.options.enableHTML) {
994
- $('a', $resetButton).html(this.options.resetText);
995
- }
996
- else {
997
- $('a', $resetButton).text(this.options.resetText);
998
- }
999
-
1000
- $('a', $resetButton).click($.proxy(function(){
1001
- this.clearSelection();
1002
- }, this));
1003
-
1004
- this.$ul.prepend($resetButton);
1005
- }
1006
- },
1007
-
1008
- /**
1009
- * Build the select all.
1010
- *
1011
- * Checks if a select all has already been created.
1012
- */
1013
- buildSelectAll: function() {
1014
- if (typeof this.options.selectAllValue === 'number') {
1015
- this.options.selectAllValue = this.options.selectAllValue.toString();
1016
- }
1017
-
1018
- var alreadyHasSelectAll = this.hasSelectAll();
1019
-
1020
- if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
1021
- && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {
1022
-
1023
- // Check whether to add a divider after the select all.
1024
- if (this.options.includeSelectAllDivider) {
1025
- this.$ul.prepend($(this.options.templates.divider));
1026
- }
1027
-
1028
- var $li = $(this.options.templates.li);
1029
- $('label', $li).addClass("checkbox");
1030
-
1031
- if (this.options.enableHTML) {
1032
- $('label', $li).html(" " + this.options.selectAllText);
1033
- }
1034
- else {
1035
- $('label', $li).text(" " + this.options.selectAllText);
1036
- }
1037
-
1038
- if (this.options.selectAllName) {
1039
- $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />');
1040
- }
1041
- else {
1042
- $('label', $li).prepend('<input type="checkbox" />');
1043
- }
1044
-
1045
- var $checkbox = $('input', $li);
1046
- $checkbox.val(this.options.selectAllValue);
1047
-
1048
- $li.addClass("multiselect-item multiselect-all");
1049
- $checkbox.parent().parent()
1050
- .addClass('multiselect-all');
1051
-
1052
- this.$ul.prepend($li);
1053
-
1054
- $checkbox.prop('checked', false);
1055
- }
1056
- },
1057
-
1058
- /**
1059
- * Builds the filter.
1060
- */
1061
- buildFilter: function() {
1062
-
1063
- // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
1064
- if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
1065
- var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
1066
-
1067
- if (this.$select.find('option').length >= enableFilterLength) {
1068
-
1069
- this.$filter = $(this.options.templates.filter);
1070
- $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);
1071
-
1072
- // Adds optional filter clear button
1073
- if(this.options.includeFilterClearBtn) {
1074
- var clearBtn = $(this.options.templates.filterClearBtn);
1075
- clearBtn.on('click', $.proxy(function(event){
1076
- clearTimeout(this.searchTimeout);
1077
-
1078
- this.query = '';
1079
- this.$filter.find('.multiselect-search').val('');
1080
- $('li', this.$ul).show().removeClass('multiselect-filter-hidden');
1081
-
1082
- this.updateSelectAll();
1083
-
1084
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1085
- this.updateOptGroups();
1086
- }
1087
-
1088
- }, this));
1089
- this.$filter.find('.input-group').append(clearBtn);
1090
- }
1091
-
1092
- this.$ul.prepend(this.$filter);
1093
-
1094
- this.$filter.val(this.query).on('click', function(event) {
1095
- event.stopPropagation();
1096
- }).on('input keydown', $.proxy(function(event) {
1097
- // Cancel enter key default behaviour
1098
- if (event.which === 13) {
1099
- event.preventDefault();
1100
- }
1101
-
1102
- // This is useful to catch "keydown" events after the browser has updated the control.
1103
- clearTimeout(this.searchTimeout);
1104
-
1105
- this.searchTimeout = this.asyncFunction($.proxy(function() {
1106
-
1107
- if (this.query !== event.target.value) {
1108
- this.query = event.target.value;
1109
-
1110
- var currentGroup, currentGroupVisible;
1111
- $.each($('li', this.$ul), $.proxy(function(index, element) {
1112
- var value = $('input', element).length > 0 ? $('input', element).val() : "";
1113
- var text = $('label', element).text();
1114
-
1115
- var filterCandidate = '';
1116
- if ((this.options.filterBehavior === 'text')) {
1117
- filterCandidate = text;
1118
- }
1119
- else if ((this.options.filterBehavior === 'value')) {
1120
- filterCandidate = value;
1121
- }
1122
- else if (this.options.filterBehavior === 'both') {
1123
- filterCandidate = text + '\n' + value;
1124
- }
1125
-
1126
- if (value !== this.options.selectAllValue && text) {
1127
-
1128
- // By default lets assume that element is not
1129
- // interesting for this search.
1130
- var showElement = false;
1131
-
1132
- if (this.options.enableCaseInsensitiveFiltering) {
1133
- filterCandidate = filterCandidate.toLowerCase();
1134
- this.query = this.query.toLowerCase();
1135
- }
1136
-
1137
- if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') {
1138
- var valueToMatch = filterCandidate.trim().substring(0, this.query.length);
1139
- if (this.query.indexOf(valueToMatch) > -1) {
1140
- showElement = true;
1141
- }
1142
- }
1143
- else if (filterCandidate.indexOf(this.query) > -1) {
1144
- showElement = true;
1145
- }
1146
-
1147
- // Toggle current element (group or group item) according to showElement boolean.
1148
- if(!showElement){
1149
- $(element).css('display', 'none');
1150
- $(element).addClass('multiselect-filter-hidden');
1151
- }
1152
- if(showElement){
1153
- $(element).css('display', 'block');
1154
- $(element).removeClass('multiselect-filter-hidden');
1155
- }
1156
-
1157
- // Differentiate groups and group items.
1158
- if ($(element).hasClass('multiselect-group')) {
1159
- // Remember group status.
1160
- currentGroup = element;
1161
- currentGroupVisible = showElement;
1162
- }
1163
- else {
1164
- // Show group name when at least one of its items is visible.
1165
- if (showElement) {
1166
- $(currentGroup).show()
1167
- .removeClass('multiselect-filter-hidden');
1168
- }
1169
-
1170
- // Show all group items when group name satisfies filter.
1171
- if (!showElement && currentGroupVisible) {
1172
- $(element).show()
1173
- .removeClass('multiselect-filter-hidden');
1174
- }
1175
- }
1176
- }
1177
- }, this));
1178
- }
1179
-
1180
- this.updateSelectAll();
1181
-
1182
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1183
- this.updateOptGroups();
1184
- }
1185
-
1186
- this.options.onFiltering(event.target);
1187
-
1188
- }, this), 300, this);
1189
- }, this));
1190
- }
1191
- }
1192
- },
1193
-
1194
- /**
1195
- * Unbinds the whole plugin.
1196
- */
1197
- destroy: function() {
1198
- this.$container.remove();
1199
- this.$select.show();
1200
-
1201
- // reset original state
1202
- this.$select.prop('disabled', this.options.wasDisabled);
1203
-
1204
- this.$select.data('multiselect', null);
1205
- },
1206
-
1207
- /**
1208
- * Refreshs the multiselect based on the selected options of the select.
1209
- */
1210
- refresh: function () {
1211
- var inputs = {};
1212
- $('li input', this.$ul).each(function() {
1213
- inputs[$(this).val()] = $(this);
1214
- });
1215
-
1216
- $('option', this.$select).each($.proxy(function (index, element) {
1217
- var $elem = $(element);
1218
- var $input = inputs[$(element).val()];
1219
-
1220
- if ($elem.is(':selected')) {
1221
- $input.prop('checked', true);
1222
-
1223
- if (this.options.selectedClass) {
1224
- $input.closest('li')
1225
- .addClass(this.options.selectedClass);
1226
- }
1227
- }
1228
- else {
1229
- $input.prop('checked', false);
1230
-
1231
- if (this.options.selectedClass) {
1232
- $input.closest('li')
1233
- .removeClass(this.options.selectedClass);
1234
- }
1235
- }
1236
-
1237
- if ($elem.is(":disabled")) {
1238
- $input.attr('disabled', 'disabled')
1239
- .prop('disabled', true)
1240
- .closest('li')
1241
- .addClass('disabled');
1242
- }
1243
- else {
1244
- $input.prop('disabled', false)
1245
- .closest('li')
1246
- .removeClass('disabled');
1247
- }
1248
- }, this));
1249
-
1250
- this.updateButtonText();
1251
- this.updateSelectAll();
1252
-
1253
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1254
- this.updateOptGroups();
1255
- }
1256
- },
1257
-
1258
- /**
1259
- * Select all options of the given values.
1260
- *
1261
- * If triggerOnChange is set to true, the on change event is triggered if
1262
- * and only if one value is passed.
1263
- *
1264
- * @param {Array} selectValues
1265
- * @param {Boolean} triggerOnChange
1266
- */
1267
- select: function(selectValues, triggerOnChange) {
1268
- if(!$.isArray(selectValues)) {
1269
- selectValues = [selectValues];
1270
- }
1271
-
1272
- for (var i = 0; i < selectValues.length; i++) {
1273
- var value = selectValues[i];
1274
-
1275
- if (value === null || value === undefined) {
1276
- continue;
1277
- }
1278
-
1279
- var $option = this.getOptionByValue(value);
1280
- var $checkbox = this.getInputByValue(value);
1281
-
1282
- if($option === undefined || $checkbox === undefined) {
1283
- continue;
1284
- }
1285
-
1286
- if (!this.options.multiple) {
1287
- this.deselectAll(false);
1288
- }
1289
-
1290
- if (this.options.selectedClass) {
1291
- $checkbox.closest('li')
1292
- .addClass(this.options.selectedClass);
1293
- }
1294
-
1295
- $checkbox.prop('checked', true);
1296
- $option.prop('selected', true);
1297
-
1298
- if (triggerOnChange) {
1299
- this.options.onChange($option, true);
1300
- }
1301
- }
1302
-
1303
- this.updateButtonText();
1304
- this.updateSelectAll();
1305
-
1306
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1307
- this.updateOptGroups();
1308
- }
1309
- },
1310
-
1311
- /**
1312
- * Clears all selected items.
1313
- */
1314
- clearSelection: function () {
1315
- this.deselectAll(false);
1316
- this.updateButtonText();
1317
- this.updateSelectAll();
1318
-
1319
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1320
- this.updateOptGroups();
1321
- }
1322
- },
1323
-
1324
- /**
1325
- * Deselects all options of the given values.
1326
- *
1327
- * If triggerOnChange is set to true, the on change event is triggered, if
1328
- * and only if one value is passed.
1329
- *
1330
- * @param {Array} deselectValues
1331
- * @param {Boolean} triggerOnChange
1332
- */
1333
- deselect: function(deselectValues, triggerOnChange) {
1334
- if(!$.isArray(deselectValues)) {
1335
- deselectValues = [deselectValues];
1336
- }
1337
-
1338
- for (var i = 0; i < deselectValues.length; i++) {
1339
- var value = deselectValues[i];
1340
-
1341
- if (value === null || value === undefined) {
1342
- continue;
1343
- }
1344
-
1345
- var $option = this.getOptionByValue(value);
1346
- var $checkbox = this.getInputByValue(value);
1347
-
1348
- if($option === undefined || $checkbox === undefined) {
1349
- continue;
1350
- }
1351
-
1352
- if (this.options.selectedClass) {
1353
- $checkbox.closest('li')
1354
- .removeClass(this.options.selectedClass);
1355
- }
1356
-
1357
- $checkbox.prop('checked', false);
1358
- $option.prop('selected', false);
1359
-
1360
- if (triggerOnChange) {
1361
- this.options.onChange($option, false);
1362
- }
1363
- }
1364
-
1365
- this.updateButtonText();
1366
- this.updateSelectAll();
1367
-
1368
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1369
- this.updateOptGroups();
1370
- }
1371
- },
1372
-
1373
- /**
1374
- * Selects all enabled & visible options.
1375
- *
1376
- * If justVisible is true or not specified, only visible options are selected.
1377
- *
1378
- * @param {Boolean} justVisible
1379
- * @param {Boolean} triggerOnSelectAll
1380
- */
1381
- selectAll: function (justVisible, triggerOnSelectAll) {
1382
-
1383
- var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
1384
- var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
1385
- var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');
1386
-
1387
- if(justVisible) {
1388
- $('input:enabled' , visibleLis).prop('checked', true);
1389
- visibleLis.addClass(this.options.selectedClass);
1390
-
1391
- $('input:enabled' , visibleLis).each($.proxy(function(index, element) {
1392
- var value = $(element).val();
1393
- var option = this.getOptionByValue(value);
1394
- $(option).prop('selected', true);
1395
- }, this));
1396
- }
1397
- else {
1398
- $('input:enabled' , allLis).prop('checked', true);
1399
- allLis.addClass(this.options.selectedClass);
1400
-
1401
- $('input:enabled' , allLis).each($.proxy(function(index, element) {
1402
- var value = $(element).val();
1403
- var option = this.getOptionByValue(value);
1404
- $(option).prop('selected', true);
1405
- }, this));
1406
- }
1407
-
1408
- $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', true);
1409
-
1410
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1411
- this.updateOptGroups();
1412
- }
1413
-
1414
- if (triggerOnSelectAll) {
1415
- this.options.onSelectAll();
1416
- }
1417
- },
1418
-
1419
- /**
1420
- * Deselects all options.
1421
- *
1422
- * If justVisible is true or not specified, only visible options are deselected.
1423
- *
1424
- * @param {Boolean} justVisible
1425
- */
1426
- deselectAll: function (justVisible, triggerOnDeselectAll) {
1427
-
1428
- var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
1429
- var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
1430
- var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');
1431
-
1432
- if(justVisible) {
1433
- $('input[type="checkbox"]:enabled' , visibleLis).prop('checked', false);
1434
- visibleLis.removeClass(this.options.selectedClass);
1435
-
1436
- $('input[type="checkbox"]:enabled' , visibleLis).each($.proxy(function(index, element) {
1437
- var value = $(element).val();
1438
- var option = this.getOptionByValue(value);
1439
- $(option).prop('selected', false);
1440
- }, this));
1441
- }
1442
- else {
1443
- $('input[type="checkbox"]:enabled' , allLis).prop('checked', false);
1444
- allLis.removeClass(this.options.selectedClass);
1445
-
1446
- $('input[type="checkbox"]:enabled' , allLis).each($.proxy(function(index, element) {
1447
- var value = $(element).val();
1448
- var option = this.getOptionByValue(value);
1449
- $(option).prop('selected', false);
1450
- }, this));
1451
- }
1452
-
1453
- $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', false);
1454
-
1455
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1456
- this.updateOptGroups();
1457
- }
1458
-
1459
- if (triggerOnDeselectAll) {
1460
- this.options.onDeselectAll();
1461
- }
1462
- },
1463
-
1464
- /**
1465
- * Rebuild the plugin.
1466
- *
1467
- * Rebuilds the dropdown, the filter and the select all option.
1468
- */
1469
- rebuild: function() {
1470
- this.$ul.html('');
1471
-
1472
- // Important to distinguish between radios and checkboxes.
1473
- this.options.multiple = this.$select.attr('multiple') === "multiple";
1474
-
1475
- this.buildSelectAll();
1476
- this.buildDropdownOptions();
1477
- this.buildFilter();
1478
-
1479
- this.updateButtonText();
1480
- this.updateSelectAll(true);
1481
-
1482
- if (this.options.enableClickableOptGroups && this.options.multiple) {
1483
- this.updateOptGroups();
1484
- }
1485
-
1486
- if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
1487
- this.disable();
1488
- }
1489
- else {
1490
- this.enable();
1491
- }
1492
-
1493
- if (this.options.dropRight) {
1494
- this.$ul.addClass('pull-right');
1495
- }
1496
- },
1497
-
1498
- /**
1499
- * The provided data will be used to build the dropdown.
1500
- */
1501
- dataprovider: function(dataprovider) {
1502
-
1503
- var groupCounter = 0;
1504
- var $select = this.$select.empty();
1505
-
1506
- $.each(dataprovider, function (index, option) {
1507
- var $tag;
1508
-
1509
- if ($.isArray(option.children)) { // create optiongroup tag
1510
- groupCounter++;
1511
-
1512
- $tag = $('<optgroup/>').attr({
1513
- label: option.label || 'Group ' + groupCounter,
1514
- disabled: !!option.disabled,
1515
- value: option.value
1516
- });
1517
-
1518
- forEach(option.children, function(subOption) { // add children option tags
1519
- var attributes = {
1520
- value: subOption.value,
1521
- label: subOption.label || subOption.value,
1522
- title: subOption.title,
1523
- selected: !!subOption.selected,
1524
- disabled: !!subOption.disabled
1525
- };
1526
-
1527
- //Loop through attributes object and add key-value for each attribute
1528
- for (var key in subOption.attributes) {
1529
- attributes['data-' + key] = subOption.attributes[key];
1530
- }
1531
- //Append original attributes + new data attributes to option
1532
- $tag.append($('<option/>').attr(attributes));
1533
- });
1534
- }
1535
- else {
1536
-
1537
- var attributes = {
1538
- 'value': option.value,
1539
- 'label': option.label || option.value,
1540
- 'title': option.title,
1541
- 'class': option['class'],
1542
- 'selected': !!option['selected'],
1543
- 'disabled': !!option['disabled']
1544
- };
1545
- //Loop through attributes object and add key-value for each attribute
1546
- for (var key in option.attributes) {
1547
- attributes['data-' + key] = option.attributes[key];
1548
- }
1549
- //Append original attributes + new data attributes to option
1550
- $tag = $('<option/>').attr(attributes);
1551
-
1552
- $tag.text(option.label || option.value);
1553
- }
1554
-
1555
- $select.append($tag);
1556
- });
1557
-
1558
- this.rebuild();
1559
- },
1560
-
1561
- /**
1562
- * Enable the multiselect.
1563
- */
1564
- enable: function() {
1565
- this.$select.prop('disabled', false);
1566
- this.$button.prop('disabled', false)
1567
- .removeClass('disabled');
1568
- },
1569
-
1570
- /**
1571
- * Disable the multiselect.
1572
- */
1573
- disable: function() {
1574
- this.$select.prop('disabled', true);
1575
- this.$button.prop('disabled', true)
1576
- .addClass('disabled');
1577
- },
1578
-
1579
- /**
1580
- * Set the options.
1581
- *
1582
- * @param {Array} options
1583
- */
1584
- setOptions: function(options) {
1585
- this.options = this.mergeOptions(options);
1586
- },
1587
-
1588
- /**
1589
- * Merges the given options with the default options.
1590
- *
1591
- * @param {Array} options
1592
- * @returns {Array}
1593
- */
1594
- mergeOptions: function(options) {
1595
- return $.extend(true, {}, this.defaults, this.options, options);
1596
- },
1597
-
1598
- /**
1599
- * Checks whether a select all checkbox is present.
1600
- *
1601
- * @returns {Boolean}
1602
- */
1603
- hasSelectAll: function() {
1604
- return $('li.multiselect-all', this.$ul).length > 0;
1605
- },
1606
-
1607
- /**
1608
- * Update opt groups.
1609
- */
1610
- updateOptGroups: function() {
1611
- var $groups = $('li.multiselect-group', this.$ul)
1612
- var selectedClass = this.options.selectedClass;
1613
-
1614
- $groups.each(function() {
1615
- var $options = $(this).nextUntil('li.multiselect-group')
1616
- .not('.multiselect-filter-hidden')
1617
- .not('.disabled');
1618
-
1619
- var checked = true;
1620
- $options.each(function() {
1621
- var $input = $('input', this);
1622
-
1623
- if (!$input.prop('checked')) {
1624
- checked = false;
1625
- }
1626
- });
1627
-
1628
- if (selectedClass) {
1629
- if (checked) {
1630
- $(this).addClass(selectedClass);
1631
- }
1632
- else {
1633
- $(this).removeClass(selectedClass);
1634
- }
1635
- }
1636
-
1637
- $('input', this).prop('checked', checked);
1638
- });
1639
- },
1640
-
1641
- /**
1642
- * Updates the select all checkbox based on the currently displayed and selected checkboxes.
1643
- */
1644
- updateSelectAll: function(notTriggerOnSelectAll) {
1645
- if (this.hasSelectAll()) {
1646
- var allBoxes = $("li:not(.multiselect-item):not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$ul);
1647
- var allBoxesLength = allBoxes.length;
1648
- var checkedBoxesLength = allBoxes.filter(":checked").length;
1649
- var selectAllLi = $("li.multiselect-all", this.$ul);
1650
- var selectAllInput = selectAllLi.find("input");
1651
-
1652
- if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {
1653
- selectAllInput.prop("checked", true);
1654
- selectAllLi.addClass(this.options.selectedClass);
1655
- }
1656
- else {
1657
- selectAllInput.prop("checked", false);
1658
- selectAllLi.removeClass(this.options.selectedClass);
1659
- }
1660
- }
1661
- },
1662
-
1663
- /**
1664
- * Update the button text and its title based on the currently selected options.
1665
- */
1666
- updateButtonText: function() {
1667
- var options = this.getSelected();
1668
-
1669
- // First update the displayed button text.
1670
- if (this.options.enableHTML) {
1671
- $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));
1672
- }
1673
- else {
1674
- $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));
1675
- }
1676
-
1677
- // Now update the title attribute of the button.
1678
- $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
1679
- },
1680
-
1681
- /**
1682
- * Get all selected options.
1683
- *
1684
- * @returns {jQUery}
1685
- */
1686
- getSelected: function() {
1687
- return $('option', this.$select).filter(":selected");
1688
- },
1689
-
1690
- /**
1691
- * Gets a select option by its value.
1692
- *
1693
- * @param {String} value
1694
- * @returns {jQuery}
1695
- */
1696
- getOptionByValue: function (value) {
1697
-
1698
- var options = $('option', this.$select);
1699
- var valueToCompare = value.toString();
1700
-
1701
- for (var i = 0; i < options.length; i = i + 1) {
1702
- var option = options[i];
1703
- if (option.value === valueToCompare) {
1704
- return $(option);
1705
- }
1706
- }
1707
- },
1708
-
1709
- /**
1710
- * Get the input (radio/checkbox) by its value.
1711
- *
1712
- * @param {String} value
1713
- * @returns {jQuery}
1714
- */
1715
- getInputByValue: function (value) {
1716
-
1717
- var checkboxes = $('li input:not(.multiselect-search)', this.$ul);
1718
- var valueToCompare = value.toString();
1719
-
1720
- for (var i = 0; i < checkboxes.length; i = i + 1) {
1721
- var checkbox = checkboxes[i];
1722
- if (checkbox.value === valueToCompare) {
1723
- return $(checkbox);
1724
- }
1725
- }
1726
- },
1727
-
1728
- /**
1729
- * Used for knockout integration.
1730
- */
1731
- updateOriginalOptions: function() {
1732
- this.originalOptions = this.$select.clone()[0].options;
1733
- },
1734
-
1735
- asyncFunction: function(callback, timeout, self) {
1736
- var args = Array.prototype.slice.call(arguments, 3);
1737
- return setTimeout(function() {
1738
- callback.apply(self || window, args);
1739
- }, timeout);
1740
- },
1741
-
1742
- setAllSelectedText: function(allSelectedText) {
1743
- this.options.allSelectedText = allSelectedText;
1744
- this.updateButtonText();
1745
- }
1746
- };
1747
-
1748
- $.fn.multiselect = function(option, parameter, extraOptions) {
1749
- return this.each(function() {
1750
- var data = $(this).data('multiselect');
1751
- var options = typeof option === 'object' && option;
1752
-
1753
- // Initialize the multiselect.
1754
- if (!data) {
1755
- data = new Multiselect(this, options);
1756
- $(this).data('multiselect', data);
1757
- }
1758
-
1759
- // Call multiselect method.
1760
- if (typeof option === 'string') {
1761
- data[option](parameter, extraOptions);
1762
-
1763
- if (option === 'destroy') {
1764
- $(this).data('multiselect', false);
1765
- }
1766
- }
1767
- });
1768
- };
1769
-
1770
- $.fn.multiselect.Constructor = Multiselect;
1771
-
1772
- $(function() {
1773
- $("select[data-role=multiselect]").multiselect();
1774
- });
1775
-
1776
- });