From 5c98d90b9e6f5d9c71100a1018f6251859be6fed Mon Sep 17 00:00:00 2001
From: Josh Caspersz <4262521+joshcaspersz@users.noreply.github.com>
Date: Wed, 15 May 2019 13:26:07 +1000
Subject: [PATCH 1/5] Optimised getSelected used in updateButtonText
---
dist/js/bootstrap-multiselect.js | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js
index 2a028b77..14811059 100644
--- a/dist/js/bootstrap-multiselect.js
+++ b/dist/js/bootstrap-multiselect.js
@@ -1684,7 +1684,23 @@
* @returns {jQUery}
*/
getSelected: function() {
- return $('option', this.$select).filter(":selected");
+ var select = this.$select[0];
+ if (select.selectedOptions !== undefined) {
+ return $(select.selectedOptions);
+ }
+
+ // selectedIndex is the index of the first option selected or -1 if nothing is selected
+ if (select.selectedIndex == -1) {
+ return [];
+ }
+
+ var selectedOptions = [];
+ for (var i = select.selectedIndex; i < select.length; i++) {
+ if (select.options[i].selected){
+ selectedOptions.push(select.options[i]);
+ }
+ }
+ return $(selectedOptions);
},
/**
From f43f0c142ab93ae9a417efe36885e1ae631a2366 Mon Sep 17 00:00:00 2001
From: Josh Caspersz <4262521+joshcaspersz@users.noreply.github.com>
Date: Wed, 15 May 2019 13:26:36 +1000
Subject: [PATCH 2/5] Optimised buildDropdownOptions
---
dist/js/bootstrap-multiselect.js | 59 +++++++++++++++++++++++---------
1 file changed, 42 insertions(+), 17 deletions(-)
diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js
index 14811059..ede0d1a2 100644
--- a/dist/js/bootstrap-multiselect.js
+++ b/dist/js/bootstrap-multiselect.js
@@ -545,33 +545,33 @@
*/
buildDropdownOptions: function() {
+ var listOptions = [];
this.$select.children().each($.proxy(function(index, element) {
-
- var $element = $(element);
+
// Support optgroups and options without a group simultaneously.
- var tag = $element.prop('tagName')
- .toLowerCase();
+ var tag = element.tagName;
- if ($element.prop('value') === this.options.selectAllValue) {
+ if (element.value === this.options.selectAllValue) {
return;
}
- if (tag === 'optgroup') {
- this.createOptgroup(element);
+ if (tag === 'OPTGROUP') {
+ listOptions.push.apply(listOptions, this.createOptgroup(element));
}
- else if (tag === 'option') {
-
- if ($element.data('role') === 'divider') {
- this.createDivider();
- }
- else {
- this.createOptionValue(element);
- }
+ else if (tag === 'OPTION') {
+ // TODO (if dividers required): Enable and add divider to listOptions
+ //if (element.getAttribute('data-role') === 'divider') {
+ // this.createDivider();
+ //}
+ //else {
+ listOptions.push(this.createOptionValueString(element));
+ //}
}
// Other illegal tags will be ignored.
}, this));
+ this.$ul[0].innerHTML += listOptions.join('');
// Bind the change event on the dropdown elements.
$(this.$ul).off('change', 'li:not(.multiselect-group) input[type="checkbox"], li:not(.multiselect-group) input[type="radio"]');
@@ -927,6 +927,28 @@
}
},
+ /**
+ * Return an option string using the given select option.
+ *
+ * @param {jQuery} element
+ */
+ createOptionValueString: function(element) {
+ var value = element.value;
+ var title = element.text;
+ var selected = element.selected;
+ var inputType = this.options.multiple ? "checkbox" : "radio";
+
+ var checkbox = '' : '">');
+ var label = '";
+
+ var liClass = (selected && this.options.selectedClass ? ' class="' + this.options.selectedClass + '"' : '');
+ var li = '
' + label + '';
+
+ // TODO: Implement: element.disabled check
+
+ return li;
+ },
+
/**
* Creates a divider using the given select option.
*
@@ -969,11 +991,14 @@
$li.addClass('disabled');
}
- this.$ul.append($li);
+ // TODO: Optimize above
+ var optGroupOptions = [$li[0].outerHTML];
$("option", group).each($.proxy(function($, group) {
- this.createOptionValue(group);
+ optGroupOptions.push(this.createOptionValueString(group));
}, this))
+
+ return optGroupOptions;
},
/**
From 332609a39d08e49fa6bea3c9247eae94bf0d0fcf Mon Sep 17 00:00:00 2001
From: Josh Caspersz <4262521+joshcaspersz@users.noreply.github.com>
Date: Wed, 15 May 2019 13:29:00 +1000
Subject: [PATCH 3/5] Optimised dropdown show/hide
---
dist/less/bootstrap-multiselect.less | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/dist/less/bootstrap-multiselect.less b/dist/less/bootstrap-multiselect.less
index deec16fe..f435ce92 100644
--- a/dist/less/bootstrap-multiselect.less
+++ b/dist/less/bootstrap-multiselect.less
@@ -133,3 +133,14 @@ span.multiselect-native-select select{
}
}
}
+
+.multiselect-container.dropdown-menu {
+ display: block;
+ visibility: hidden;
+ height: 0;
+}
+
+.open > .multiselect-container.dropdown-menu {
+ visibility: inherit;
+ height: auto;
+}
\ No newline at end of file
From ce7e3039dba9d54cc2c241d0ddc8e32d28993b98 Mon Sep 17 00:00:00 2001
From: Josh Caspersz <4262521+joshcaspersz@users.noreply.github.com>
Date: Wed, 15 May 2019 13:35:29 +1000
Subject: [PATCH 4/5] Optimised search filter
---
dist/js/bootstrap-multiselect.js | 2 --
dist/less/bootstrap-multiselect.less | 5 +++++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js
index ede0d1a2..cd8a5511 100644
--- a/dist/js/bootstrap-multiselect.js
+++ b/dist/js/bootstrap-multiselect.js
@@ -1171,11 +1171,9 @@
// Toggle current element (group or group item) according to showElement boolean.
if(!showElement){
- $(element).css('display', 'none');
$(element).addClass('multiselect-filter-hidden');
}
if(showElement){
- $(element).css('display', 'block');
$(element).removeClass('multiselect-filter-hidden');
}
diff --git a/dist/less/bootstrap-multiselect.less b/dist/less/bootstrap-multiselect.less
index f435ce92..e225ca17 100644
--- a/dist/less/bootstrap-multiselect.less
+++ b/dist/less/bootstrap-multiselect.less
@@ -76,11 +76,16 @@ span.multiselect-native-select select{
> li {
padding: 0;
+ overflow: hidden;
> a.multiselect-all label {
font-weight: bold;
}
+ &.multiselect-filter-hidden {
+ height: 0;
+ }
+
&.multiselect-group label {
margin: 0;
padding: 3px 20px 3px 20px;
From 71e535c3dc5e998cfc04be0546c28f817bdb695f Mon Sep 17 00:00:00 2001
From: Josh Caspersz <4262521+joshcaspersz@users.noreply.github.com>
Date: Wed, 15 May 2019 15:01:28 +1000
Subject: [PATCH 5/5] createOptionValueString XSS fix
---
dist/js/bootstrap-multiselect.js | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dist/js/bootstrap-multiselect.js b/dist/js/bootstrap-multiselect.js
index cd8a5511..e5446b1e 100644
--- a/dist/js/bootstrap-multiselect.js
+++ b/dist/js/bootstrap-multiselect.js
@@ -933,8 +933,8 @@
* @param {jQuery} element
*/
createOptionValueString: function(element) {
- var value = element.value;
- var title = element.text;
+ var value = this.escapeHtml(element.value);
+ var title = this.escapeHtml(element.text);
var selected = element.selected;
var inputType = this.options.multiple ? "checkbox" : "radio";
@@ -949,6 +949,26 @@
return li;
},
+ /**
+ * Escapes a string for use in HTML
+ *
+ * @param {String} value
+ * @returns {String}
+ */
+ escapeHtml: function(s) {
+ var ESC_MAP = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+
+ return s.replace(/[&<>'"]/g, function(c) {
+ return ESC_MAP[c];
+ });
+ },
+
/**
* Creates a divider using the given select option.
*