in www/assets/bootstrap-select.js [545:728]
createLi: function () {
var that = this,
_li = [],
optID = 0,
titleOption = document.createElement('option'),
liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure liObj is correct
// Helper functions
/**
* @param content
* @param [index]
* @param [classes]
* @param [optgroup]
* @returns {string}
*/
var generateLI = function (content, index, classes, optgroup) {
return '<li' +
((typeof classes !== 'undefined' & '' !== classes) ? ' class="' + classes + '"' : '') +
((typeof index !== 'undefined' & null !== index) ? ' data-original-index="' + index + '"' : '') +
((typeof optgroup !== 'undefined' & null !== optgroup) ? 'data-optgroup="' + optgroup + '"' : '') +
'>' + content + '</li>';
};
/**
* @param text
* @param [classes]
* @param [inline]
* @param [tokens]
* @returns {string}
*/
var generateA = function (text, classes, inline, tokens) {
return '<a tabindex="0"' +
(typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
(inline ? ' style="' + inline + '"' : '') +
(that.options.liveSearchNormalize ? ' data-normalized-text="' + normalizeToBase(htmlEscape($(text).html())) + '"' : '') +
(typeof tokens !== 'undefined' || tokens !== null ? ' data-tokens="' + tokens + '"' : '') +
' role="option">' + text +
'<span class="' + that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark"></span>' +
'</a>';
};
if (this.options.title && !this.multiple) {
// this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased
// since liObj is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended
liIndex--;
if (!this.$element.find('.bs-title-option').length) {
// Use native JS to prepend option (faster)
var element = this.$element[0];
titleOption.className = 'bs-title-option';
titleOption.innerHTML = this.options.title;
titleOption.value = '';
element.insertBefore(titleOption, element.firstChild);
// Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
// the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
// if so, the select will have the data-selected attribute
var $opt = $(element.options[element.selectedIndex]);
if ($opt.attr('selected') === undefined && this.$element.data('selected') === undefined) {
titleOption.selected = true;
}
}
}
this.$element.find('option').each(function (index) {
var $this = $(this);
liIndex++;
if ($this.hasClass('bs-title-option')) return;
// Get the class and text for the option
var optionClass = this.className || '',
inline = this.style.cssText,
text = $this.data('content') ? $this.data('content') : $this.html(),
tokens = $this.data('tokens') ? $this.data('tokens') : null,
subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $this.data('subtext') + '</small>' : '',
icon = typeof $this.data('icon') !== 'undefined' ? '<span class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></span> ' : '',
$parent = $this.parent(),
isOptgroup = $parent[0].tagName === 'OPTGROUP',
isOptgroupDisabled = isOptgroup && $parent[0].disabled,
isDisabled = this.disabled || isOptgroupDisabled;
if (icon !== '' && isDisabled) {
icon = '<span>' + icon + '</span>';
}
if (that.options.hideDisabled && (isDisabled && !isOptgroup || isOptgroupDisabled)) {
liIndex--;
return;
}
if (!$this.data('content')) {
// Prepend any icon and append any subtext to the main text.
text = icon + '<span class="text">' + text + subtext + '</span>';
}
if (isOptgroup && $this.data('divider') !== true) {
if (that.options.hideDisabled && isDisabled) {
if ($parent.data('allOptionsDisabled') === undefined) {
var $options = $parent.children();
$parent.data('allOptionsDisabled', $options.filter(':disabled').length === $options.length);
}
if ($parent.data('allOptionsDisabled')) {
liIndex--;
return;
}
}
var optGroupClass = ' ' + $parent[0].className || '';
if ($this.index() === 0) { // Is it the first option of the optgroup?
optID += 1;
// Get the opt group label
var label = $parent[0].label,
labelSubtext = typeof $parent.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $parent.data('subtext') + '</small>' : '',
labelIcon = $parent.data('icon') ? '<span class="' + that.options.iconBase + ' ' + $parent.data('icon') + '"></span> ' : '';
label = labelIcon + '<span class="text">' + htmlEscape(label) + labelSubtext + '</span>';
if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?
liIndex++;
_li.push(generateLI('', null, 'divider', optID + 'div'));
}
liIndex++;
_li.push(generateLI(label, null, 'dropdown-header' + optGroupClass, optID));
}
if (that.options.hideDisabled && isDisabled) {
liIndex--;
return;
}
_li.push(generateLI(generateA(text, 'opt ' + optionClass + optGroupClass, inline, tokens), index, '', optID));
} else if ($this.data('divider') === true) {
_li.push(generateLI('', index, 'divider'));
} else if ($this.data('hidden') === true) {
_li.push(generateLI(generateA(text, optionClass, inline, tokens), index, 'hidden is-hidden'));
} else {
var showDivider = this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP';
// if previous element is not an optgroup and hideDisabled is true
if (!showDivider && that.options.hideDisabled) {
// get previous elements
var $prev = $(this).prevAll();
for (var i = 0; i < $prev.length; i++) {
// find the first element in the previous elements that is an optgroup
if ($prev[i].tagName === 'OPTGROUP') {
var optGroupDistance = 0;
// loop through the options in between the current option and the optgroup
// and check if they are hidden or disabled
for (var d = 0; d < i; d++) {
var prevOption = $prev[d];
if (prevOption.disabled || $(prevOption).data('hidden') === true) optGroupDistance++;
}
// if all of the options between the current option and the optgroup are hidden or disabled, show the divider
if (optGroupDistance === i) showDivider = true;
break;
}
}
}
if (showDivider) {
liIndex++;
_li.push(generateLI('', null, 'divider', optID + 'div'));
}
_li.push(generateLI(generateA(text, optionClass, inline, tokens), index));
}
that.liObj[index] = liIndex;
});
//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
if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {
this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
}
return _li.join('');
},